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