Loading core/java/android/content/pm/IPackageManager.aidl +1 −2 Original line number Diff line number Diff line Loading @@ -379,8 +379,7 @@ interface IPackageManager { /** * Logs process start information (including APK hash) to the security log. */ void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile, int pid); void logAppProcessStartIfNeeded(String packageName, String processName, int uid, String seinfo, String apkFile, int pid); /** * As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}. Loading services/core/java/com/android/server/am/ProcessList.java +2 −2 Original line number Diff line number Diff line Loading @@ -2540,8 +2540,8 @@ public final class ProcessList { app.hostingRecord.getName() != null ? app.hostingRecord.getName() : ""); try { AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid, app.seInfo, app.info.sourceDir, pid); AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.info.packageName, app.processName, app.uid, app.seInfo, app.info.sourceDir, pid); } catch (RemoteException ex) { // Ignore } Loading services/core/java/com/android/server/pm/PackageManagerService.java +5 −22 Original line number Diff line number Diff line Loading @@ -2232,8 +2232,7 @@ public class PackageManagerService extends IPackageManager.Stub // Send installed broadcasts if the package is not a static shared lib. if (res.pkg.getStaticSharedLibName() == null) { mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash( res.pkg.getBaseApkPath()); mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath()); // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps Loading Loading @@ -2497,13 +2496,6 @@ public class PackageManagerService extends IPackageManager.Stub } } for (int i = 0, size = filesToChecksum.size(); i < size; ++i) { final File file = filesToChecksum.get(i).second; if (!file.exists()) { throw new IllegalStateException("File not found: " + file.getPath()); } } final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates( trustedInstallers) : null; Loading Loading @@ -25806,25 +25798,16 @@ public class PackageManagerService extends IPackageManager.Stub * @hide */ @Override public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile, int pid) { public void logAppProcessStartIfNeeded(String packageName, String processName, int uid, String seinfo, String apkFile, int pid) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } if (!SecurityLog.isLoggingEnabled()) { return; } Bundle data = new Bundle(); data.putLong("startTimestamp", System.currentTimeMillis()); data.putString("processName", processName); data.putInt("uid", uid); data.putString("seinfo", seinfo); data.putString("apkFile", apkFile); data.putInt("pid", pid); Message msg = mProcessLoggingHandler.obtainMessage( ProcessLoggingHandler.LOG_APP_PROCESS_START_MSG); msg.setData(data); mProcessLoggingHandler.sendMessage(msg); mProcessLoggingHandler.logAppProcessStart(mContext, this, apkFile, packageName, processName, uid, seinfo, pid); } public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) { services/core/java/com/android/server/pm/ProcessLoggingHandler.java +137 −50 Original line number Diff line number Diff line Loading @@ -16,29 +16,47 @@ package com.android.server.pm; import static android.content.pm.PackageManager.EXTRA_CHECKSUMS; import android.app.admin.SecurityLog; import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApkChecksum; import android.content.pm.Checksum; import android.content.pm.IPackageManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcelable; import android.os.RemoteException; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; import com.android.internal.os.BackgroundThread; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import android.util.Slog; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public final class ProcessLoggingHandler extends Handler { private static final String TAG = "ProcessLoggingHandler"; static final int LOG_APP_PROCESS_START_MSG = 1; static final int INVALIDATE_BASE_APK_HASH_MSG = 2; private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap(); private static final int LOG_APP_PROCESS_START_MSG = 1; private static final int CHECKSUM_TYPE = Checksum.TYPE_WHOLE_SHA256; static class LoggingInfo { public String apkHash = null; public List<Bundle> pendingLogEntries = new ArrayList<>(); } // Apk path to logging info map. private final ArrayMap<String, LoggingInfo> mLoggingInfo = new ArrayMap<>(); ProcessLoggingHandler() { super(BackgroundThread.getHandler().getLooper()); Loading @@ -49,64 +67,133 @@ public final class ProcessLoggingHandler extends Handler { switch (msg.what) { case LOG_APP_PROCESS_START_MSG: { Bundle bundle = msg.getData(); long startTimestamp = bundle.getLong("startTimestamp"); String processName = bundle.getString("processName"); int uid = bundle.getInt("uid"); String seinfo = bundle.getString("seinfo"); String apkFile = bundle.getString("apkFile"); int pid = bundle.getInt("pid"); long startTimestamp = bundle.getLong("startTimestamp"); String apkHash = computeStringHashOfApk(apkFile); String apkHash = bundle.getString("apkHash"); SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName, startTimestamp, uid, pid, seinfo, apkHash); break; } case INVALIDATE_BASE_APK_HASH_MSG: { Bundle bundle = msg.getData(); mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile")); break; } } } void invalidateProcessLoggingBaseApkHash(String apkPath) { void logAppProcessStart(Context context, IPackageManager pms, String apkFile, String packageName, String processName, int uid, String seinfo, int pid) { Bundle data = new Bundle(); data.putString("apkFile", apkPath); Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG); msg.setData(data); sendMessage(msg); } data.putLong("startTimestamp", System.currentTimeMillis()); data.putString("processName", processName); data.putInt("uid", uid); data.putString("seinfo", seinfo); data.putInt("pid", pid); private String computeStringHashOfApk(String apkFile) { if (apkFile == null) { return "No APK"; enqueueSecurityLogEvent(data, "No APK"); return; } // Check cached apk hash. boolean requestChecksums; final LoggingInfo loggingInfo; synchronized (mLoggingInfo) { LoggingInfo cached = mLoggingInfo.get(apkFile); requestChecksums = cached == null; if (requestChecksums) { // Create a new pending cache entry. cached = new LoggingInfo(); mLoggingInfo.put(apkFile, cached); } loggingInfo = cached; } synchronized (loggingInfo) { // Still pending? if (!TextUtils.isEmpty(loggingInfo.apkHash)) { enqueueSecurityLogEvent(data, loggingInfo.apkHash); return; } loggingInfo.pendingLogEntries.add(data); } if (!requestChecksums) { return; } String apkHash = mProcessLoggingBaseApkHashes.get(apkFile); if (apkHash == null) { // Request base checksums when first added entry. // Capturing local loggingInfo to still log even if hash was invalidated. try { byte[] hash = computeHashOfApkFile(apkFile); pms.requestChecksums(packageName, false, 0, CHECKSUM_TYPE, null, new IntentSender((IIntentSender) new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { processChecksums(loggingInfo, intent); } }), context.getUserId()); } catch (RemoteException e) { Slog.e(TAG, "requestChecksums() failed", e); processChecksums(loggingInfo, null); } } void processChecksums(final LoggingInfo loggingInfo, Intent intent) { Parcelable[] parcelables = intent.getParcelableArrayExtra(EXTRA_CHECKSUMS); ApkChecksum[] checksums = Arrays.copyOf(parcelables, parcelables.length, ApkChecksum[].class); for (ApkChecksum checksum : checksums) { if (checksum.getType() == CHECKSUM_TYPE) { processChecksum(loggingInfo, checksum.getValue()); break; } } } void processChecksum(final LoggingInfo loggingInfo, final byte[] hash) { final String apkHash; if (hash != null) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < hash.length; i++) { sb.append(String.format("%02x", hash[i])); } apkHash = sb.toString(); mProcessLoggingBaseApkHashes.put(apkFile, apkHash); } catch (IOException | NoSuchAlgorithmException e) { Slog.w(TAG, "computeStringHashOfApk() failed", e); } else { apkHash = "Failed to count APK hash"; } List<Bundle> pendingLogEntries; synchronized (loggingInfo) { if (!TextUtils.isEmpty(loggingInfo.apkHash)) { return; } loggingInfo.apkHash = apkHash; pendingLogEntries = loggingInfo.pendingLogEntries; loggingInfo.pendingLogEntries = null; } if (pendingLogEntries != null) { for (Bundle data : pendingLogEntries) { enqueueSecurityLogEvent(data, apkHash); } return apkHash != null ? apkHash : "Failed to count APK hash"; } } void enqueueSecurityLogEvent(Bundle data, String apkHash) { data.putString("apkHash", apkHash); Message msg = this.obtainMessage(LOG_APP_PROCESS_START_MSG); msg.setData(data); this.sendMessage(msg); } private byte[] computeHashOfApkFile(String packageArchiveLocation) throws IOException, NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); FileInputStream input = new FileInputStream(new File(packageArchiveLocation)); byte[] buffer = new byte[65536]; int size; while ((size = input.read(buffer)) > 0) { md.update(buffer, 0, size); void invalidateBaseApkHash(String apkFile) { synchronized (mLoggingInfo) { mLoggingInfo.remove(apkFile); } input.close(); return md.digest(); } } Loading
core/java/android/content/pm/IPackageManager.aidl +1 −2 Original line number Diff line number Diff line Loading @@ -379,8 +379,7 @@ interface IPackageManager { /** * Logs process start information (including APK hash) to the security log. */ void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile, int pid); void logAppProcessStartIfNeeded(String packageName, String processName, int uid, String seinfo, String apkFile, int pid); /** * As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}. Loading
services/core/java/com/android/server/am/ProcessList.java +2 −2 Original line number Diff line number Diff line Loading @@ -2540,8 +2540,8 @@ public final class ProcessList { app.hostingRecord.getName() != null ? app.hostingRecord.getName() : ""); try { AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid, app.seInfo, app.info.sourceDir, pid); AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.info.packageName, app.processName, app.uid, app.seInfo, app.info.sourceDir, pid); } catch (RemoteException ex) { // Ignore } Loading
services/core/java/com/android/server/pm/PackageManagerService.java +5 −22 Original line number Diff line number Diff line Loading @@ -2232,8 +2232,7 @@ public class PackageManagerService extends IPackageManager.Stub // Send installed broadcasts if the package is not a static shared lib. if (res.pkg.getStaticSharedLibName() == null) { mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash( res.pkg.getBaseApkPath()); mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath()); // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps Loading Loading @@ -2497,13 +2496,6 @@ public class PackageManagerService extends IPackageManager.Stub } } for (int i = 0, size = filesToChecksum.size(); i < size; ++i) { final File file = filesToChecksum.get(i).second; if (!file.exists()) { throw new IllegalStateException("File not found: " + file.getPath()); } } final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates( trustedInstallers) : null; Loading Loading @@ -25806,25 +25798,16 @@ public class PackageManagerService extends IPackageManager.Stub * @hide */ @Override public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile, int pid) { public void logAppProcessStartIfNeeded(String packageName, String processName, int uid, String seinfo, String apkFile, int pid) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } if (!SecurityLog.isLoggingEnabled()) { return; } Bundle data = new Bundle(); data.putLong("startTimestamp", System.currentTimeMillis()); data.putString("processName", processName); data.putInt("uid", uid); data.putString("seinfo", seinfo); data.putString("apkFile", apkFile); data.putInt("pid", pid); Message msg = mProcessLoggingHandler.obtainMessage( ProcessLoggingHandler.LOG_APP_PROCESS_START_MSG); msg.setData(data); mProcessLoggingHandler.sendMessage(msg); mProcessLoggingHandler.logAppProcessStart(mContext, this, apkFile, packageName, processName, uid, seinfo, pid); } public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) {
services/core/java/com/android/server/pm/ProcessLoggingHandler.java +137 −50 Original line number Diff line number Diff line Loading @@ -16,29 +16,47 @@ package com.android.server.pm; import static android.content.pm.PackageManager.EXTRA_CHECKSUMS; import android.app.admin.SecurityLog; import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApkChecksum; import android.content.pm.Checksum; import android.content.pm.IPackageManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcelable; import android.os.RemoteException; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; import com.android.internal.os.BackgroundThread; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import android.util.Slog; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public final class ProcessLoggingHandler extends Handler { private static final String TAG = "ProcessLoggingHandler"; static final int LOG_APP_PROCESS_START_MSG = 1; static final int INVALIDATE_BASE_APK_HASH_MSG = 2; private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap(); private static final int LOG_APP_PROCESS_START_MSG = 1; private static final int CHECKSUM_TYPE = Checksum.TYPE_WHOLE_SHA256; static class LoggingInfo { public String apkHash = null; public List<Bundle> pendingLogEntries = new ArrayList<>(); } // Apk path to logging info map. private final ArrayMap<String, LoggingInfo> mLoggingInfo = new ArrayMap<>(); ProcessLoggingHandler() { super(BackgroundThread.getHandler().getLooper()); Loading @@ -49,64 +67,133 @@ public final class ProcessLoggingHandler extends Handler { switch (msg.what) { case LOG_APP_PROCESS_START_MSG: { Bundle bundle = msg.getData(); long startTimestamp = bundle.getLong("startTimestamp"); String processName = bundle.getString("processName"); int uid = bundle.getInt("uid"); String seinfo = bundle.getString("seinfo"); String apkFile = bundle.getString("apkFile"); int pid = bundle.getInt("pid"); long startTimestamp = bundle.getLong("startTimestamp"); String apkHash = computeStringHashOfApk(apkFile); String apkHash = bundle.getString("apkHash"); SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName, startTimestamp, uid, pid, seinfo, apkHash); break; } case INVALIDATE_BASE_APK_HASH_MSG: { Bundle bundle = msg.getData(); mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile")); break; } } } void invalidateProcessLoggingBaseApkHash(String apkPath) { void logAppProcessStart(Context context, IPackageManager pms, String apkFile, String packageName, String processName, int uid, String seinfo, int pid) { Bundle data = new Bundle(); data.putString("apkFile", apkPath); Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG); msg.setData(data); sendMessage(msg); } data.putLong("startTimestamp", System.currentTimeMillis()); data.putString("processName", processName); data.putInt("uid", uid); data.putString("seinfo", seinfo); data.putInt("pid", pid); private String computeStringHashOfApk(String apkFile) { if (apkFile == null) { return "No APK"; enqueueSecurityLogEvent(data, "No APK"); return; } // Check cached apk hash. boolean requestChecksums; final LoggingInfo loggingInfo; synchronized (mLoggingInfo) { LoggingInfo cached = mLoggingInfo.get(apkFile); requestChecksums = cached == null; if (requestChecksums) { // Create a new pending cache entry. cached = new LoggingInfo(); mLoggingInfo.put(apkFile, cached); } loggingInfo = cached; } synchronized (loggingInfo) { // Still pending? if (!TextUtils.isEmpty(loggingInfo.apkHash)) { enqueueSecurityLogEvent(data, loggingInfo.apkHash); return; } loggingInfo.pendingLogEntries.add(data); } if (!requestChecksums) { return; } String apkHash = mProcessLoggingBaseApkHashes.get(apkFile); if (apkHash == null) { // Request base checksums when first added entry. // Capturing local loggingInfo to still log even if hash was invalidated. try { byte[] hash = computeHashOfApkFile(apkFile); pms.requestChecksums(packageName, false, 0, CHECKSUM_TYPE, null, new IntentSender((IIntentSender) new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { processChecksums(loggingInfo, intent); } }), context.getUserId()); } catch (RemoteException e) { Slog.e(TAG, "requestChecksums() failed", e); processChecksums(loggingInfo, null); } } void processChecksums(final LoggingInfo loggingInfo, Intent intent) { Parcelable[] parcelables = intent.getParcelableArrayExtra(EXTRA_CHECKSUMS); ApkChecksum[] checksums = Arrays.copyOf(parcelables, parcelables.length, ApkChecksum[].class); for (ApkChecksum checksum : checksums) { if (checksum.getType() == CHECKSUM_TYPE) { processChecksum(loggingInfo, checksum.getValue()); break; } } } void processChecksum(final LoggingInfo loggingInfo, final byte[] hash) { final String apkHash; if (hash != null) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < hash.length; i++) { sb.append(String.format("%02x", hash[i])); } apkHash = sb.toString(); mProcessLoggingBaseApkHashes.put(apkFile, apkHash); } catch (IOException | NoSuchAlgorithmException e) { Slog.w(TAG, "computeStringHashOfApk() failed", e); } else { apkHash = "Failed to count APK hash"; } List<Bundle> pendingLogEntries; synchronized (loggingInfo) { if (!TextUtils.isEmpty(loggingInfo.apkHash)) { return; } loggingInfo.apkHash = apkHash; pendingLogEntries = loggingInfo.pendingLogEntries; loggingInfo.pendingLogEntries = null; } if (pendingLogEntries != null) { for (Bundle data : pendingLogEntries) { enqueueSecurityLogEvent(data, apkHash); } return apkHash != null ? apkHash : "Failed to count APK hash"; } } void enqueueSecurityLogEvent(Bundle data, String apkHash) { data.putString("apkHash", apkHash); Message msg = this.obtainMessage(LOG_APP_PROCESS_START_MSG); msg.setData(data); this.sendMessage(msg); } private byte[] computeHashOfApkFile(String packageArchiveLocation) throws IOException, NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); FileInputStream input = new FileInputStream(new File(packageArchiveLocation)); byte[] buffer = new byte[65536]; int size; while ((size = input.read(buffer)) > 0) { md.update(buffer, 0, size); void invalidateBaseApkHash(String apkFile) { synchronized (mLoggingInfo) { mLoggingInfo.remove(apkFile); } input.close(); return md.digest(); } }