blob: b26b6940a1af27a6d31a46f851251c62c327ab27 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm.dex;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
import android.os.SystemClock;
import android.util.Slog;
import android.util.jar.StrictJarFile;
import com.android.internal.art.ArtStatsLog;
import com.android.server.pm.PackageManagerService;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
/** Utils class to report ART metrics to statsd. */
public class ArtStatsLogUtils {
private static final String TAG = ArtStatsLogUtils.class.getSimpleName();
private static final String PROFILE_DEX_METADATA = "primary.prof";
private static final String VDEX_DEX_METADATA = "primary.vdex";
private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY =
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
private static final int ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED =
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED =
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK =
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK =
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
private static final Map<Integer, Integer> COMPILATION_REASON_MAP = new HashMap();
static {
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog.
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);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_POST_BOOT, ArtStatsLog.
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);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_FAST, ArtStatsLog.
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);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
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);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_AB_OTA, ArtStatsLog.
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);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_CMDLINE,
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);
}
private static final Map<String, Integer> COMPILE_FILTER_MAP = new HashMap();
static {
COMPILE_FILTER_MAP.put("error", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ERROR);
COMPILE_FILTER_MAP.put("unknown", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN);
COMPILE_FILTER_MAP.put("assume-verified", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ASSUMED_VERIFIED);
COMPILE_FILTER_MAP.put("extract", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EXTRACT);
COMPILE_FILTER_MAP.put("verify", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_VERIFY);
COMPILE_FILTER_MAP.put("quicken", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_QUICKEN);
COMPILE_FILTER_MAP.put("space-profile", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE_PROFILE);
COMPILE_FILTER_MAP.put("space", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE);
COMPILE_FILTER_MAP.put("speed-profile", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED_PROFILE);
COMPILE_FILTER_MAP.put("speed", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED);
COMPILE_FILTER_MAP.put("everything-profile", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING_PROFILE);
COMPILE_FILTER_MAP.put("everything", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING);
COMPILE_FILTER_MAP.put("run-from-apk", ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK);
COMPILE_FILTER_MAP.put("run-from-apk-fallback",
ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK);
COMPILE_FILTER_MAP.put("run-from-vdex-fallback",
ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK);
}
private static final Map<String, Integer> ISA_MAP = new HashMap();
static {
ISA_MAP.put("arm", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM);
ISA_MAP.put("arm64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM64);
ISA_MAP.put("x86", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86);
ISA_MAP.put("x86_64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86_64);
ISA_MAP.put("mips", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS);
ISA_MAP.put("mips64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS64);
}
public static void writeStatsLog(
ArtStatsLogger logger,
long sessionId,
String compilerFilter,
int uid,
long compileTime,
String dexMetadataPath,
int compilationReason,
int result,
int apkType,
String isa,
String apkPath) {
int dexMetadataType = getDexMetadataType(dexMetadataPath);
logger.write(
sessionId,
uid,
compilationReason,
compilerFilter,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
result,
dexMetadataType,
apkType,
isa);
logger.write(
sessionId,
uid,
compilationReason,
compilerFilter,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_COUNTER_BYTES,
getDexBytes(apkPath),
dexMetadataType,
apkType,
isa);
logger.write(
sessionId,
uid,
compilationReason,
compilerFilter,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME_COUNTER_MILLIS,
compileTime,
dexMetadataType,
apkType,
isa);
}
public static int getApkType(String path, String baseApkPath, String[] splitApkPaths) {
if (path.equals(baseApkPath)) {
return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE;
} else if(Arrays.stream(splitApkPaths).anyMatch(p->p.equals(path))) {
return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_SPLIT;
} else{
return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_UNKNOWN;
}
}
private static long getDexBytes(String apkPath) {
StrictJarFile jarFile = null;
long dexBytes = 0;
try {
jarFile = new StrictJarFile(apkPath,
/*verify=*/ false,
/*signatureSchemeRollbackProtectionsEnforced=*/ false);
Iterator<ZipEntry> it = jarFile.iterator();
Pattern p = Pattern.compile("classes(\\d)*[.]dex");
Matcher m = p.matcher("");
while (it.hasNext()) {
ZipEntry entry = it.next();
m.reset(entry.getName());
if (m.matches()) {
dexBytes += entry.getSize();
}
}
return dexBytes;
} catch (IOException ignore) {
Slog.e(TAG, "Error when parsing APK " + apkPath);
return -1L;
} finally {
try {
if (jarFile != null) {
jarFile.close();
}
} catch (IOException ignore) {
}
}
}
private static int getDexMetadataType(String dexMetadataPath) {
if (dexMetadataPath == null) {
return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE;
}
StrictJarFile jarFile = null;
try {
jarFile = new StrictJarFile(dexMetadataPath,
/*verify=*/ false,
/*signatureSchemeRollbackProtectionsEnforced=*/false);
boolean hasProfile = findFileName(jarFile, PROFILE_DEX_METADATA);
boolean hasVdex = findFileName(jarFile, VDEX_DEX_METADATA);
if (hasProfile && hasVdex) {
return ArtStatsLog.
ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX;
} else if (hasProfile) {
return ArtStatsLog.
ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE;
} else if (hasVdex) {
return ArtStatsLog.
ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX;
} else {
return ArtStatsLog.
ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN;
}
} catch (IOException ignore) {
Slog.e(TAG, "Error when parsing dex metadata " + dexMetadataPath);
return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_ERROR;
} finally {
try {
if (jarFile != null) {
jarFile.close();
}
} catch (IOException ignore) {
}
}
}
private static boolean findFileName(StrictJarFile jarFile, String filename) throws IOException {
Iterator<ZipEntry> it = jarFile.iterator();
while (it.hasNext()) {
ZipEntry entry = it.next();
if (entry.getName().equals(filename)) {
return true;
}
}
return false;
}
public static class ArtStatsLogger {
public void write(
long sessionId,
int uid,
int compilationReason,
String compilerFilter,
int kind,
long value,
int dexMetadataType,
int apkType,
String isa) {
ArtStatsLog.write(
ArtStatsLog.ART_DATUM_REPORTED,
sessionId,
uid,
COMPILE_FILTER_MAP.getOrDefault(compilerFilter, ArtStatsLog.
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN),
COMPILATION_REASON_MAP.getOrDefault(compilationReason, ArtStatsLog.
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN),
/*timestamp_millis=*/ SystemClock.uptimeMillis(),
ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
kind,
value,
dexMetadataType,
apkType,
ISA_MAP.getOrDefault(isa,
ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN));
}
}
}