1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.server.pm.dex;
18 
19 import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
20 import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
21 import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
22 import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
23 import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
24 
25 import android.app.job.JobParameters;
26 import android.os.SystemClock;
27 import android.util.Slog;
28 import android.util.jar.StrictJarFile;
29 
30 import com.android.internal.art.ArtStatsLog;
31 import com.android.server.pm.BackgroundDexOptService;
32 import com.android.server.pm.PackageManagerService;
33 
34 import java.io.IOException;
35 import java.util.Arrays;
36 import java.util.HashMap;
37 import java.util.Iterator;
38 import java.util.Map;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41 import java.util.zip.ZipEntry;
42 
43 /** Utils class to report ART metrics to statsd. */
44 public class ArtStatsLogUtils {
45     private static final String TAG = ArtStatsLogUtils.class.getSimpleName();
46     private static final String PROFILE_DEX_METADATA = "primary.prof";
47     private static final String VDEX_DEX_METADATA = "primary.vdex";
48 
49     private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY =
50             ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
51     private static final int ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED =
52             ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
53     private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED =
54             ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
55 
56     private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK =
57             ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
58     private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK =
59             ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
60 
61     private static final Map<Integer, Integer> COMPILATION_REASON_MAP = new HashMap();
62 
63     static {
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT)64         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog.
65                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BOOT_AFTER_OTA, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT_AFTER_OTA)66         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BOOT_AFTER_OTA, ArtStatsLog.
67                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT_AFTER_OTA);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_POST_BOOT, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_POST_BOOT)68         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_POST_BOOT, ArtStatsLog.
69                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_POST_BOOT);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL)70         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL, ArtStatsLog.
71                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_FAST, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_FAST)72         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_FAST, ArtStatsLog.
73                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_FAST);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK)74         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK, ArtStatsLog.
75                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY, ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY)76         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
77                 ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED, ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED)78         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
79                 ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED, ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED)80         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
81                 ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BACKGROUND_DEXOPT, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BG_DEXOPT)82         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BACKGROUND_DEXOPT, ArtStatsLog.
83                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BG_DEXOPT);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_AB_OTA, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_AB_OTA)84         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_AB_OTA, ArtStatsLog.
85                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_AB_OTA);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE, ArtStatsLog. ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE)86         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE,
87                 ArtStatsLog.
88                         ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_CMDLINE, ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_CMDLINE)89         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_CMDLINE,
90                 ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_CMDLINE);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_SHARED, ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED)91         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_SHARED,
92                 ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED);
93     }
94 
95     private static final Map<String, Integer> COMPILE_FILTER_MAP = new HashMap();
96 
97     static {
98         COMPILE_FILTER_MAP.put("error", ArtStatsLog.
99                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ERROR);
100         COMPILE_FILTER_MAP.put("unknown", ArtStatsLog.
101                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN);
102         COMPILE_FILTER_MAP.put("assume-verified", ArtStatsLog.
103                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ASSUMED_VERIFIED);
104         COMPILE_FILTER_MAP.put("extract", ArtStatsLog.
105                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EXTRACT);
106         COMPILE_FILTER_MAP.put("verify", ArtStatsLog.
107                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_VERIFY);
108         COMPILE_FILTER_MAP.put("quicken", ArtStatsLog.
109                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_QUICKEN);
110         COMPILE_FILTER_MAP.put("space-profile", ArtStatsLog.
111                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE_PROFILE);
112         COMPILE_FILTER_MAP.put("space", ArtStatsLog.
113                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE);
114         COMPILE_FILTER_MAP.put("speed-profile", ArtStatsLog.
115                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED_PROFILE);
116         COMPILE_FILTER_MAP.put("speed", ArtStatsLog.
117                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED);
118         COMPILE_FILTER_MAP.put("everything-profile", ArtStatsLog.
119                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING_PROFILE);
120         COMPILE_FILTER_MAP.put("everything", ArtStatsLog.
121                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING);
122         COMPILE_FILTER_MAP.put("run-from-apk", ArtStatsLog.
123                 ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK);
124         COMPILE_FILTER_MAP.put("run-from-apk-fallback",
125                 ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK);
126         COMPILE_FILTER_MAP.put("run-from-vdex-fallback",
127                 ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK);
128     }
129 
130     private static final Map<String, Integer> ISA_MAP = new HashMap();
131 
132     static {
133         ISA_MAP.put("arm", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM);
134         ISA_MAP.put("arm64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM64);
135         ISA_MAP.put("x86", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86);
136         ISA_MAP.put("x86_64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86_64);
137         ISA_MAP.put("mips", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS);
138         ISA_MAP.put("mips64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS64);
139     }
140 
writeStatsLog( ArtStatsLogger logger, long sessionId, String compilerFilter, int uid, long compileTime, String dexMetadataPath, int compilationReason, int result, int apkType, String isa, String apkPath)141     public static void writeStatsLog(
142             ArtStatsLogger logger,
143             long sessionId,
144             String compilerFilter,
145             int uid,
146             long compileTime,
147             String dexMetadataPath,
148             int compilationReason,
149             int result,
150             int apkType,
151             String isa,
152             String apkPath) {
153         int dexMetadataType = getDexMetadataType(dexMetadataPath);
154         logger.write(
155                 sessionId,
156                 uid,
157                 compilationReason,
158                 compilerFilter,
159                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
160                 result,
161                 dexMetadataType,
162                 apkType,
163                 isa);
164         logger.write(
165                 sessionId,
166                 uid,
167                 compilationReason,
168                 compilerFilter,
169                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_COUNTER_BYTES,
170                 getDexBytes(apkPath),
171                 dexMetadataType,
172                 apkType,
173                 isa);
174         logger.write(
175                 sessionId,
176                 uid,
177                 compilationReason,
178                 compilerFilter,
179                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME_COUNTER_MILLIS,
180                 compileTime,
181                 dexMetadataType,
182                 apkType,
183                 isa);
184     }
185 
getApkType(String path, String baseApkPath, String[] splitApkPaths)186     public static int getApkType(String path, String baseApkPath, String[] splitApkPaths) {
187         if (path.equals(baseApkPath)) {
188             return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE;
189         } else if(Arrays.stream(splitApkPaths).anyMatch(p->p.equals(path))) {
190             return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_SPLIT;
191         } else{
192             return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_UNKNOWN;
193         }
194     }
195 
getDexBytes(String apkPath)196     private static long getDexBytes(String apkPath) {
197         StrictJarFile jarFile = null;
198         long dexBytes = 0;
199         try {
200             jarFile = new StrictJarFile(apkPath,
201                     /*verify=*/ false,
202                     /*signatureSchemeRollbackProtectionsEnforced=*/ false);
203             Iterator<ZipEntry> it = jarFile.iterator();
204             Pattern p = Pattern.compile("classes(\\d)*[.]dex");
205             Matcher m = p.matcher("");
206             while (it.hasNext()) {
207                 ZipEntry entry = it.next();
208                 m.reset(entry.getName());
209                 if (m.matches()) {
210                     dexBytes += entry.getSize();
211                 }
212             }
213             return dexBytes;
214         } catch (IOException ignore) {
215             Slog.e(TAG, "Error when parsing APK " + apkPath);
216             return -1L;
217         } finally {
218             try {
219                 if (jarFile != null) {
220                     jarFile.close();
221                 }
222             } catch (IOException ignore) {
223             }
224         }
225     }
226 
getDexMetadataType(String dexMetadataPath)227     private static int getDexMetadataType(String dexMetadataPath) {
228         if (dexMetadataPath == null) {
229             return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE;
230         }
231         StrictJarFile jarFile = null;
232         try {
233             jarFile = new StrictJarFile(dexMetadataPath,
234                     /*verify=*/ false,
235                     /*signatureSchemeRollbackProtectionsEnforced=*/false);
236             boolean hasProfile = findFileName(jarFile, PROFILE_DEX_METADATA);
237             boolean hasVdex = findFileName(jarFile, VDEX_DEX_METADATA);
238             if (hasProfile && hasVdex) {
239                 return ArtStatsLog.
240                     ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX;
241             } else if (hasProfile) {
242                 return ArtStatsLog.
243                     ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE;
244             } else if (hasVdex) {
245                 return ArtStatsLog.
246                     ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX;
247             } else {
248                 return ArtStatsLog.
249                     ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN;
250             }
251         } catch (IOException ignore) {
252             Slog.e(TAG, "Error when parsing dex metadata " + dexMetadataPath);
253             return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_ERROR;
254         } finally {
255             try {
256                 if (jarFile != null) {
257                     jarFile.close();
258                 }
259             } catch (IOException ignore) {
260             }
261         }
262     }
263 
findFileName(StrictJarFile jarFile, String filename)264     private static boolean findFileName(StrictJarFile jarFile, String filename) throws IOException {
265         Iterator<ZipEntry> it = jarFile.iterator();
266         while (it.hasNext()) {
267             ZipEntry entry = it.next();
268             if (entry.getName().equals(filename)) {
269                 return true;
270             }
271         }
272         return false;
273     }
274 
275     public static class ArtStatsLogger {
write( long sessionId, int uid, int compilationReason, String compilerFilter, int kind, long value, int dexMetadataType, int apkType, String isa)276         public void write(
277                 long sessionId,
278                 int uid,
279                 int compilationReason,
280                 String compilerFilter,
281                 int kind,
282                 long value,
283                 int dexMetadataType,
284                 int apkType,
285                 String isa) {
286             ArtStatsLog.write(
287                     ArtStatsLog.ART_DATUM_REPORTED,
288                     sessionId,
289                     uid,
290                     COMPILE_FILTER_MAP.getOrDefault(compilerFilter, ArtStatsLog.
291                             ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN),
292                     COMPILATION_REASON_MAP.getOrDefault(compilationReason, ArtStatsLog.
293                             ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN),
294                     /*timestamp_millis=*/ SystemClock.uptimeMillis(),
295                     ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
296                     kind,
297                     value,
298                     dexMetadataType,
299                     apkType,
300                     ISA_MAP.getOrDefault(isa,
301                             ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN),
302                     ArtStatsLog.ART_DATUM_REPORTED__GC__ART_GC_COLLECTOR_TYPE_UNKNOWN,
303                     ArtStatsLog.ART_DATUM_REPORTED__UFFD_SUPPORT__ART_UFFD_SUPPORT_UNKNOWN);
304         }
305     }
306 
307     private static final Map<Integer, Integer> STATUS_MAP =
308             Map.of(BackgroundDexOptService.STATUS_UNSPECIFIED,
309                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN,
310                     BackgroundDexOptService.STATUS_OK,
311                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED,
312                     BackgroundDexOptService.STATUS_ABORT_BY_CANCELLATION,
313                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_CANCELLATION,
314                     BackgroundDexOptService.STATUS_ABORT_NO_SPACE_LEFT,
315                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_NO_SPACE_LEFT,
316                     BackgroundDexOptService.STATUS_ABORT_THERMAL,
317                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_THERMAL,
318                     BackgroundDexOptService.STATUS_ABORT_BATTERY,
319                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BATTERY,
320                     BackgroundDexOptService.STATUS_DEX_OPT_FAILED,
321                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED,
322                     BackgroundDexOptService.STATUS_FATAL_ERROR,
323                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_FATAL_ERROR);
324 
325     /** Helper class to write background dexopt job stats to statsd. */
326     public static class BackgroundDexoptJobStatsLogger {
327         /** Writes background dexopt job stats to statsd. */
write(@ackgroundDexOptService.Status int status, @JobParameters.StopReason int cancellationReason, long durationMs)328         public void write(@BackgroundDexOptService.Status int status,
329                           @JobParameters.StopReason int cancellationReason,
330                           long durationMs) {
331             ArtStatsLog.write(
332                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED,
333                     STATUS_MAP.getOrDefault(status,
334                             ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN),
335                     cancellationReason,
336                     durationMs,
337                     0);  // deprecated, used to be durationIncludingSleepMs
338         }
339     }
340 }
341