2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "dnssd_analytics.h"
18 #include "mDNSMacOSX.h"
19 #include "uds_daemon.h"
21 #if MDNSRESPONDER_SUPPORTS(APPLE, ANALYTICS)
24 #include <CoreAnalytics/CoreAnalytics.h>
25 typedef xpc_object_t COREANALYTICS_RETURNS_RETAINED
26 (^event_create_block_t
)(void);
28 #define UNSET_STR "unset"
32 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
34 // Local aggregate counters to track request counts
36 mDNSlocal
uint64_t sCacheUsage_UnicastHitCount
= 0;
37 mDNSlocal
uint64_t sCacheUsage_UnicastMissCount
= 0;
38 mDNSlocal
uint64_t sCacheUsage_MulticastHitCount
= 0;
39 mDNSlocal
uint64_t sCacheUsage_MulticastMissCount
= 0;
41 mDNSlocal
uint64_t sCacheRequest_UnicastHitCount
= 0;
42 mDNSlocal
uint64_t sCacheRequest_UnicastMissCount
= 0;
43 mDNSlocal
uint64_t sCacheRequest_MulticastHitCount
= 0;
44 mDNSlocal
uint64_t sCacheRequest_MulticastMissCount
= 0;
46 #if COMPILER_LIKES_PRAGMA_MARK
48 #pragma mark - Private CacheUsage Functions
52 dnssd_analytics_post_cache_request_count(CacheRequestType inType
, CacheState inState
, uint64_t inRequestCount
)
54 event_create_block_t create_event
;
59 dict
= xpc_dictionary_create(NULL
, NULL
, 0);
60 xpc_dictionary_set_string(dict
, "requestType", inType
== CacheRequestType_multicast
? "multicast" : "unicast");
61 xpc_dictionary_set_string(dict
, "cacheState", inState
== CacheState_hit
? "hit" : "miss");
62 xpc_dictionary_set_uint64(dict
, "requestCount", inRequestCount
);
65 posted
= analytics_send_event_lazy("com.apple.mDNSResponder.CacheUsage.request", create_event
);
67 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_WARNING
, "com.apple.mDNSResponder.CacheUsage.request: Failed to post");
72 dnssd_analytics_post_cache_request_counts()
74 if (sCacheRequest_UnicastHitCount
> 0) {
75 dnssd_analytics_post_cache_request_count(CacheRequestType_unicast
, CacheState_hit
, sCacheRequest_UnicastHitCount
);
76 sCacheRequest_UnicastHitCount
= 0;
78 if (sCacheRequest_UnicastMissCount
> 0) {
79 dnssd_analytics_post_cache_request_count(CacheRequestType_unicast
, CacheState_miss
, sCacheRequest_UnicastMissCount
);
80 sCacheRequest_UnicastMissCount
= 0;
82 if (sCacheRequest_MulticastHitCount
> 0) {
83 dnssd_analytics_post_cache_request_count(CacheRequestType_multicast
, CacheState_hit
, sCacheRequest_MulticastHitCount
);
84 sCacheRequest_MulticastHitCount
= 0;
86 if (sCacheRequest_MulticastMissCount
> 0) {
87 dnssd_analytics_post_cache_request_count(CacheRequestType_multicast
, CacheState_miss
, sCacheRequest_MulticastMissCount
);
88 sCacheRequest_MulticastMissCount
= 0;
93 dnssd_analytics_post_cache_usage_counts_for_type(CacheRequestType inType
, uint64_t inHitCount
, uint64_t inMissCount
)
95 event_create_block_t create_event
;
100 dict
= xpc_dictionary_create(NULL
, NULL
, 0);
101 xpc_dictionary_set_string(dict
, "requestType", inType
== CacheRequestType_multicast
? "multicast" : "unicast");
102 xpc_dictionary_set_uint64(dict
, "hitCount", inHitCount
);
103 xpc_dictionary_set_uint64(dict
, "missCount", inMissCount
);
106 posted
= analytics_send_event_lazy("com.apple.mDNSResponder.CacheUsage.entries", create_event
);
108 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_WARNING
, "com.apple.mDNSResponder.CacheUsage.entries: Failed to post");
113 dnssd_analytics_post_cache_usage_counts()
115 if (sCacheUsage_MulticastHitCount
|| sCacheUsage_MulticastMissCount
) {
116 dnssd_analytics_post_cache_usage_counts_for_type(CacheRequestType_multicast
, sCacheUsage_MulticastHitCount
, sCacheUsage_MulticastMissCount
);
117 sCacheUsage_MulticastHitCount
= 0;
118 sCacheUsage_MulticastMissCount
= 0;
120 if (sCacheUsage_UnicastHitCount
|| sCacheUsage_UnicastMissCount
) {
121 dnssd_analytics_post_cache_usage_counts_for_type(CacheRequestType_unicast
, sCacheUsage_UnicastHitCount
, sCacheUsage_UnicastMissCount
);
122 sCacheUsage_UnicastHitCount
= 0;
123 sCacheUsage_UnicastMissCount
= 0;
127 #if COMPILER_LIKES_PRAGMA_MARK
129 #pragma mark - Exported CacheUsage Functions
133 dnssd_analytics_update_cache_request(CacheRequestType inType
, CacheState inState
)
135 if (inType
== CacheRequestType_unicast
) {
136 if (inState
== CacheState_hit
) {
137 sCacheRequest_UnicastHitCount
++;
138 } else if (inState
== CacheState_miss
) {
139 sCacheRequest_UnicastMissCount
++;
141 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_WARNING
, "dnssd_analytics_update_cache_request: unknown CacheState %d for unicast", inState
);
143 } else if (inType
== CacheRequestType_multicast
) {
144 if (inState
== CacheState_hit
) {
145 sCacheRequest_MulticastHitCount
++;
146 } else if (inState
== CacheState_miss
) {
147 sCacheRequest_MulticastMissCount
++;
149 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_WARNING
, "dnssd_analytics_update_cache_request: unknown CacheState %d for multicast", inState
);
152 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_WARNING
, "dnssd_analytics_update_cache_request: unknown CacheRequestType %d", inType
);
157 dnssd_analytics_update_cache_usage_counts(uint32_t inHitMulticastCount
, uint32_t inMissMulticastCount
, uint32_t inHitUnicastCount
, uint32_t inMissUnicastCount
)
159 sCacheUsage_MulticastHitCount
+= inHitMulticastCount
;
160 sCacheUsage_MulticastMissCount
+= inMissMulticastCount
;
161 sCacheUsage_UnicastHitCount
+= inHitUnicastCount
;
162 sCacheUsage_UnicastMissCount
+= inMissUnicastCount
;
165 #endif // CACHE_ANALYTICS
167 #if MDNSRESPONDER_SUPPORTS(APPLE, WAB_ANALYTICS)
169 #if COMPILER_LIKES_PRAGMA_MARK
171 #pragma mark - Exported WABUsage Functions
175 dnssd_analytics_post_WAB_usage_event_count(WABUsageKind inKind
, WABUsageType inType
, WABUsageEvent inEvent
, uint64_t inEventCount
)
177 event_create_block_t create_event
;
179 char * kind
= UNSET_STR
;
180 char * type
= UNSET_STR
;
181 char * event
= UNSET_STR
;
183 if (analytics_send_event_lazy
) {
185 case WABUsageKind_results
: {
189 case WABUsageKind_session
: {
193 case WABUsageKind_operation
: {
200 case WABUsageType_enumeration
: {
201 type
= "enumeration";
204 case WABUsageType_query
: {
208 case WABUsageType_push
: {
212 case WABUsageType_llq
: {
219 case WABUsageEvent_positive
: {
223 case WABUsageEvent_negative
: {
227 case WABUsageEvent_null
: {
231 case WABUsageEvent_error
: {
236 case WABUsageEvent_connected
: {
240 case WABUsageEvent_session
: {
244 case WABUsageEvent_reset
: {
248 case WABUsageEvent_idledOut
: {
252 case WABUsageEvent_goAway
: {
256 case WABUsageEvent_resumedGood
: {
257 event
= "resumedGood";
260 case WABUsageEvent_resumedBad
: {
261 event
= "resumedBad";
265 case WABUsageEvent_succeeded
: {
269 case WABUsageEvent_rejected
: {
273 case WABUsageEvent_dsoni
: {
277 case WABUsageEvent_answered
: {
285 dict
= xpc_dictionary_create(NULL
, NULL
, 0);
286 xpc_dictionary_set_string(dict
, "kind", kind
);
287 xpc_dictionary_set_string(dict
, "type", type
);
288 xpc_dictionary_set_string(dict
, "event", event
);
289 xpc_dictionary_set_uint64(dict
, "eventCount", inEventCount
);
292 posted
= analytics_send_event_lazy("com.apple.mDNSResponder.CacheUsage.entries", create_event
);
294 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_WARNING
, "com.apple.mDNSResponder.CacheUsage.entries: Failed to post");
299 #endif // WAB_ANALYTICS
301 #if MDNSRESPONDER_SUPPORTS(APPLE, ANALYTICS)
302 #if COMPILER_LIKES_PRAGMA_MARK
304 #pragma mark - Exported Analytics Functions
308 dnssd_analytics_init()
310 static dispatch_once_t sInitAnalyticsOnce
= 0;
311 static dispatch_queue_t sAnalyticsQueue
= NULL
;
312 dispatch_once(&sInitAnalyticsOnce
, ^{
313 sAnalyticsQueue
= dispatch_queue_create("com.apple.mDNSResponder.analytics-reporting-queue", DISPATCH_QUEUE_SERIAL
);
314 xpc_object_t criteria
= xpc_dictionary_create(NULL
, NULL
, 0);
315 xpc_dictionary_set_bool(criteria
, XPC_ACTIVITY_REPEATING
, true);
316 xpc_dictionary_set_bool(criteria
, XPC_ACTIVITY_ALLOW_BATTERY
, true);
317 xpc_dictionary_set_int64(criteria
, XPC_ACTIVITY_DELAY
, XPC_ACTIVITY_INTERVAL_1_DAY
);
318 xpc_dictionary_set_int64(criteria
, XPC_ACTIVITY_GRACE_PERIOD
, XPC_ACTIVITY_INTERVAL_5_MIN
);
319 xpc_dictionary_set_string(criteria
, XPC_ACTIVITY_PRIORITY
, XPC_ACTIVITY_PRIORITY_MAINTENANCE
);
321 xpc_activity_register("com.apple.mDNSResponder.analytics.daily", criteria
, ^(xpc_activity_t activity
) {
322 if (xpc_activity_should_defer(activity
)) {
323 if (xpc_activity_set_state(activity
, XPC_ACTIVITY_STATE_DEFER
)) {
324 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_INFO
, "com.apple.mDNSResponder.analytics.daily: Asked to defer");
326 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_ERROR
, "com.apple.mDNSResponder.analytics.daily: Asked to defer but failed to set state");
329 dispatch_async(sAnalyticsQueue
, ^{
330 #if MDNSRESPONDER_SUPPORTS(APPLE, ANALYTICS)
332 mDNS_Lock(&mDNSStorage
);
333 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
334 dnssd_analytics_post_cache_request_counts();
335 dnssd_analytics_post_cache_usage_counts();
336 #endif // CACHE_ANALYTICS
337 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_INFO
, "Analytics Posted");
338 mDNS_Unlock(&mDNSStorage
);
339 KQueueUnlock("Analytics Update");
342 if (!xpc_activity_set_state(activity
, XPC_ACTIVITY_STATE_DONE
)) {
343 LogRedact(MDNS_LOG_CATEGORY_ANALYTICS
, MDNS_LOG_ERROR
, "com.apple.mDNSResponder.analytics.daily: Analytics XPC_ACTIVITY_STATE_DONE failed");
347 xpc_release(criteria
);