Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 197b1678 authored by Rubin Xu's avatar Rubin Xu Committed by Android (Google) Code Review
Browse files

Merge "Log app process start from ActivityManagerService"

parents c0faa69c 7f70d438
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -1475,6 +1475,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    final ServiceThread mHandlerThread;
    final MainHandler mHandler;
    final UiHandler mUiHandler;
    final ProcessStartLogger mProcessStartLogger;
    PackageManagerInternal mPackageManagerInt;
@@ -2452,6 +2453,8 @@ public final class ActivityManagerService extends ActivityManagerNative
        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,
@@ -3552,6 +3555,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                    app.processName, hostingType,
                    hostingNameStr != null ? hostingNameStr : "");
            mProcessStartLogger.logIfNeededLocked(app, startResult);
            if (app.persistent) {
                Watchdog.getInstance().processStarted(app.processName, startResult.pid);
            }
@@ -6634,6 +6639,8 @@ public final class ActivityManagerService extends ActivityManagerNative
            }
        }, dumpheapFilter);
        mProcessStartLogger.registerListener(mContext);
        // Let system services know.
        mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+151 −0
Original line number Diff line number Diff line
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.auditing.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