Merge "Moving app process logging from AMS to PMS" into nyc-dev
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e3fb161..a0238fb 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -316,6 +316,12 @@
int getApplicationEnabledSetting(in String packageName, int userId);
/**
+ * Logs process start information (including APK hash) to the security log.
+ */
+ void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile,
+ int pid);
+
+ /**
* As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}.
*/
void flushPackageRestrictionsAsUser(in int userId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 467fc49..cd4d472 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1488,7 +1488,6 @@
final ServiceThread mHandlerThread;
final MainHandler mHandler;
final UiHandler mUiHandler;
- final ProcessStartLogger mProcessStartLogger;
PackageManagerInternal mPackageManagerInt;
@@ -2460,8 +2459,6 @@
mHandler = new MainHandler(mHandlerThread.getLooper());
mUiHandler = new UiHandler();
- mProcessStartLogger = new ProcessStartLogger();
-
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
@@ -3594,7 +3591,12 @@
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
- mProcessStartLogger.logIfNeededLocked(app, startResult);
+ try {
+ AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
+ app.info.seinfo, app.info.sourceDir, startResult.pid);
+ } catch (RemoteException ex) {
+ // Ignore
+ }
if (app.persistent) {
Watchdog.getInstance().processStarted(app.processName, startResult.pid);
@@ -6537,8 +6539,6 @@
}
}, dumpheapFilter);
- mProcessStartLogger.registerListener(mContext);
-
// Let system services know.
mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
diff --git a/services/core/java/com/android/server/am/ProcessStartLogger.java b/services/core/java/com/android/server/am/ProcessStartLogger.java
deleted file mode 100644
index 39fbeb5..0000000
--- a/services/core/java/com/android/server/am/ProcessStartLogger.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.android.server.am;
-
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-
-import android.app.AppGlobals;
-import android.app.admin.SecurityLog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.Process.ProcessStartResult;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-
-/**
- * A class that logs process start information (including APK hash) to the security log.
- */
-class ProcessStartLogger {
- private static final String CLASS_NAME = "ProcessStartLogger";
- private static final String TAG = TAG_WITH_CLASS_NAME ? CLASS_NAME : TAG_AM;
-
- final HandlerThread mHandlerProcessLoggingThread;
- Handler mHandlerProcessLogging;
- // Should only access in mHandlerProcessLoggingThread
- final HashMap<String, String> mProcessLoggingApkHashes;
-
- ProcessStartLogger() {
- mHandlerProcessLoggingThread = new HandlerThread(CLASS_NAME,
- Process.THREAD_PRIORITY_BACKGROUND);
- mProcessLoggingApkHashes = new HashMap();
- }
-
- void logIfNeededLocked(ProcessRecord app, ProcessStartResult startResult) {
- if (!SecurityLog.isLoggingEnabled()) {
- return;
- }
- if (!mHandlerProcessLoggingThread.isAlive()) {
- mHandlerProcessLoggingThread.start();
- mHandlerProcessLogging = new Handler(mHandlerProcessLoggingThread.getLooper());
- }
- mHandlerProcessLogging.post(new ProcessLoggingRunnable(app, startResult,
- System.currentTimeMillis()));
- }
-
- void registerListener(Context context) {
- IntentFilter packageChangedFilter = new IntentFilter();
- packageChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
- || Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
- int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- getSendingUserId());
- String packageName = intent.getData().getSchemeSpecificPart();
- try {
- ApplicationInfo info = AppGlobals.getPackageManager().getApplicationInfo(
- packageName, 0, userHandle);
- invaildateCache(info.sourceDir);
- } catch (RemoteException e) {
- }
- }
- }
- }, packageChangedFilter);
- }
-
- private void invaildateCache(final String apkPath) {
- if (mHandlerProcessLogging != null) {
- mHandlerProcessLogging.post(new Runnable() {
- @Override
- public void run() {
- mProcessLoggingApkHashes.remove(apkPath);
- }
- });
- }
- }
-
- private class ProcessLoggingRunnable implements Runnable {
-
- private final ProcessRecord app;
- private final Process.ProcessStartResult startResult;
- private final long startTimestamp;
-
- public ProcessLoggingRunnable(ProcessRecord app, Process.ProcessStartResult startResult,
- long startTimestamp){
- this.app = app;
- this.startResult = startResult;
- this.startTimestamp = startTimestamp;
- }
-
- @Override
- public void run() {
- String apkHash = computeStringHashOfApk(app);
- SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START,
- app.processName,
- startTimestamp,
- app.uid,
- startResult.pid,
- app.info.seinfo,
- apkHash);
- }
-
- private String computeStringHashOfApk(ProcessRecord app){
- final String apkFile = app.info.sourceDir;
- if(apkFile == null) {
- return "No APK";
- }
- String apkHash = mProcessLoggingApkHashes.get(apkFile);
- if (apkHash == null) {
- try {
- byte[] hash = computeHashOfApkFile(apkFile);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < hash.length; i++) {
- sb.append(String.format("%02x", hash[i]));
- }
- apkHash = sb.toString();
- mProcessLoggingApkHashes.put(apkFile, apkHash);
- } catch (IOException | NoSuchAlgorithmException e) {
- Slog.w(TAG, "computeStringHashOfApk() failed", e);
- }
- }
- return apkHash != null ? apkHash : "Failed to count APK hash";
- }
-
- 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);
- }
- input.close();
- return md.digest();
- }
- }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d2fd762..442643a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -106,6 +106,7 @@
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
+import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -459,6 +460,8 @@
final PackageHandler mHandler;
+ private final ProcessLoggingHandler mProcessLoggingHandler;
+
/**
* Messages for {@link #mHandler} that need to wait for system ready before
* being dispatched.
@@ -1712,6 +1715,8 @@
// Send installed broadcasts if the install/update is not ephemeral
if (!isEphemeral(res.pkg)) {
+ mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
+
// Send added for users that see the package for the first time
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/, null /*targetPackage*/,
@@ -2096,6 +2101,7 @@
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
+ mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
File dataDir = Environment.getDataDirectory();
@@ -19458,4 +19464,26 @@
return new ArrayList<>(mPackages.values());
}
}
+
+ /**
+ * Logs process start information (including base APK hash) to the security log.
+ * @hide
+ */
+ public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo,
+ String apkFile, int pid) {
+ 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);
+ }
}
diff --git a/services/core/java/com/android/server/pm/ProcessLoggingHandler.java b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
new file mode 100644
index 0000000..c47dda4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 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;
+
+import android.app.admin.SecurityLog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+
+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;
+
+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();
+
+ ProcessLoggingHandler() {
+ super(BackgroundThread.getHandler().getLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case LOG_APP_PROCESS_START_MSG: {
+ Bundle bundle = msg.getData();
+ 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);
+ 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) {
+ Bundle data = new Bundle();
+ data.putString("apkFile", apkPath);
+ Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG);
+ msg.setData(data);
+ sendMessage(msg);
+ }
+
+ private String computeStringHashOfApk(String apkFile) {
+ if (apkFile == null) {
+ return "No APK";
+ }
+ String apkHash = mProcessLoggingBaseApkHashes.get(apkFile);
+ if (apkHash == null) {
+ try {
+ byte[] hash = computeHashOfApkFile(apkFile);
+ 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);
+ }
+ }
+ return apkHash != null ? apkHash : "Failed to count APK hash";
+ }
+
+ 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);
+ }
+ input.close();
+ return md.digest();
+ }
+}