/ OSX / utilities / SecCoreAnalytics.m
SecCoreAnalytics.m
  1  /*
  2   * Copyright (c) 2018 Apple Inc. All Rights Reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   *
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   *
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   *
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  #import "SecCoreAnalytics.h"
 25  #import <CoreAnalytics/CoreAnalytics.h>
 26  #import <SoftLinking/SoftLinking.h>
 27  #import <Availability.h>
 28  #import <sys/sysctl.h>
 29  
 30  NSString* const SecCoreAnalyticsValue = @"value";
 31  
 32  
 33  void SecCoreAnalyticsSendValue(CFStringRef _Nonnull eventName, int64_t value)
 34  {
 35      [SecCoreAnalytics sendEvent:(__bridge NSString*)eventName
 36                            event:@{
 37                                SecCoreAnalyticsValue: [NSNumber numberWithLong:value],
 38                            }];
 39  }
 40  
 41  void SecCoreAnalyticsSendKernEntropyHealth()
 42  {
 43      size_t sz_int = sizeof(int);
 44      size_t sz_uint = sizeof(unsigned int);
 45      size_t sz_tv = sizeof(struct timeval);
 46  
 47      int startup_done;
 48      unsigned int adaptive_proportion_failure_count = 0;
 49      unsigned int adaptive_proportion_max_observation_count = 0;
 50      unsigned int adaptive_proportion_reset_count = 0;
 51      unsigned int repetition_failure_count = 0;
 52      unsigned int repetition_max_observation_count = 0;
 53      unsigned int repetition_reset_count = 0;
 54  
 55      int rv = sysctlbyname("kern.entropy.health.startup_done", &startup_done, &sz_int, NULL, 0);
 56      rv |= sysctlbyname("kern.entropy.health.adaptive_proportion_test.failure_count", &adaptive_proportion_failure_count, &sz_uint, NULL, 0);
 57      rv |= sysctlbyname("kern.entropy.health.adaptive_proportion_test.max_observation_count", &adaptive_proportion_max_observation_count, &sz_uint, NULL, 0);
 58      rv |= sysctlbyname("kern.entropy.health.adaptive_proportion_test.reset_count", &adaptive_proportion_reset_count, &sz_uint, NULL, 0);
 59      rv |= sysctlbyname("kern.entropy.health.repetition_count_test.failure_count", &repetition_failure_count, &sz_uint, NULL, 0);
 60      rv |= sysctlbyname("kern.entropy.health.repetition_count_test.max_observation_count", &repetition_max_observation_count, &sz_uint, NULL, 0);
 61      rv |= sysctlbyname("kern.entropy.health.repetition_count_test.reset_count", &repetition_reset_count, &sz_uint, NULL, 0);
 62  
 63      // Round up to next power of two.
 64      if (adaptive_proportion_reset_count > 0) {
 65          adaptive_proportion_reset_count =
 66              1U << (sizeof(unsigned int) * 8 - __builtin_clz(adaptive_proportion_reset_count));
 67      }
 68  
 69      // Round up to next power of two.
 70      if (repetition_reset_count > 0) {
 71          repetition_reset_count =
 72              1U << (sizeof(unsigned int) * 8 - __builtin_clz(repetition_reset_count));
 73      }
 74  
 75      // Default to not submitting uptime, except on failure.
 76      int uptime = -1;
 77  
 78      if (adaptive_proportion_failure_count > 0 || repetition_failure_count > 0) {
 79          time_t now;
 80          time(&now);
 81  
 82          struct timeval boottime;
 83          int mib[2] = { CTL_KERN, KERN_BOOTTIME };
 84          rv |= sysctl(mib, 2, &boottime, &sz_tv, NULL, 0);
 85  
 86          // Submit uptime in minutes.
 87          uptime = (int)((now - boottime.tv_sec) / 60);
 88      }
 89  
 90      if (rv) {
 91          return;
 92      }
 93  
 94      [SecCoreAnalytics sendEventLazy:@"com.apple.kern.entropyHealth" builder:^NSDictionary<NSString *,NSObject *> * _Nonnull{
 95          return @{
 96              @"uptime" : @(uptime),
 97              @"startup_done" : @(startup_done),
 98              @"adaptive_proportion_failure_count" : @(adaptive_proportion_failure_count),
 99              @"adaptive_proportion_max_observation_count" : @(adaptive_proportion_max_observation_count),
100              @"adaptive_proportion_reset_count" : @(adaptive_proportion_reset_count),
101              @"repetition_failure_count" : @(repetition_failure_count),
102              @"repetition_max_observation_count" : @(repetition_max_observation_count),
103              @"repetition_reset_count" : @(repetition_reset_count)
104          };
105      }];
106  }
107  
108  @implementation SecCoreAnalytics
109  
110  SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CoreAnalytics);
111  
112  SOFT_LINK_FUNCTION(CoreAnalytics, AnalyticsSendEvent, soft_AnalyticsSendEvent, \
113      void, (NSString* eventName, NSDictionary<NSString*,NSObject*>* eventPayload),(eventName, eventPayload));
114  SOFT_LINK_FUNCTION(CoreAnalytics, AnalyticsSendEventLazy, soft_AnalyticsSendEventLazy, \
115      void, (NSString* eventName, NSDictionary<NSString*,NSObject*>* (^eventPayloadBuilder)(void)),(eventName, eventPayloadBuilder));
116  
117  + (void)sendEvent:(NSString*) eventName event:(NSDictionary<NSString*,NSObject*>*)event
118  {
119      if (isCoreAnalyticsAvailable()) {
120          soft_AnalyticsSendEvent(eventName, event);
121      }
122  }
123  
124  + (void)sendEventLazy:(NSString*) eventName builder:(NSDictionary<NSString*,NSObject*>* (^)(void))builder
125  {
126      if (isCoreAnalyticsAvailable()) {
127          soft_AnalyticsSendEventLazy(eventName, builder);
128      }
129  }
130  
131  @end