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

Commit a65f1c58 authored by Lais Andrade's avatar Lais Andrade
Browse files

Fix NPE in ShutdownCheckPoints dumpDetails method.

Change-Id: I5e39f229be8d6a2e582cd8988755478766f1fa69
Fix: 274105604
Test: ShutdownCheckPointsTest
parent b301516b
Loading
Loading
Loading
Loading
+40 −33
Original line number Diff line number Diff line
@@ -121,23 +121,25 @@ public final class ShutdownCheckPoints {

    @VisibleForTesting
    void recordCheckPointInternal(@Nullable String reason) {
        recordCheckPointInternal(new SystemServerCheckPoint(mInjector, reason));
        recordCheckPointInternal(new SystemServerCheckPoint(mInjector.currentTimeMillis(), reason));
        Slog.v(TAG, "System server shutdown checkpoint recorded");
    }

    @VisibleForTesting
    void recordCheckPointInternal(int callerProcessId, @Nullable String reason) {
        long timestamp = mInjector.currentTimeMillis();
        recordCheckPointInternal(callerProcessId == Process.myPid()
                ? new SystemServerCheckPoint(mInjector, reason)
                : new BinderCheckPoint(mInjector, callerProcessId, reason));
                ? new SystemServerCheckPoint(timestamp, reason)
                : new BinderCheckPoint(timestamp, callerProcessId, reason));
        Slog.v(TAG, "Binder shutdown checkpoint recorded with pid=" + callerProcessId);
    }

    @VisibleForTesting
    void recordCheckPointInternal(String intentName, String packageName, @Nullable String reason) {
        long timestamp = mInjector.currentTimeMillis();
        recordCheckPointInternal("android".equals(packageName)
                ? new SystemServerCheckPoint(mInjector, reason)
                : new IntentCheckPoint(mInjector, intentName, packageName, reason));
                ? new SystemServerCheckPoint(timestamp, reason)
                : new IntentCheckPoint(timestamp, intentName, packageName, reason));
        Slog.v(TAG, String.format("Shutdown intent checkpoint recorded intent=%s from package=%s",
                intentName, packageName));
    }
@@ -156,7 +158,7 @@ public final class ShutdownCheckPoints {
            records = new ArrayList<>(mCheckPoints);
        }
        for (CheckPoint record : records) {
            record.dump(printWriter);
            record.dump(mInjector, printWriter);
            printWriter.println();
        }
    }
@@ -185,12 +187,12 @@ public final class ShutdownCheckPoints {
        private final long mTimestamp;
        @Nullable private final String mReason;

        CheckPoint(Injector injector, @Nullable String reason) {
            mTimestamp = injector.currentTimeMillis();
        CheckPoint(long timestamp, @Nullable String reason) {
            mTimestamp = timestamp;
            mReason = reason;
        }

        final void dump(PrintWriter printWriter) {
        final void dump(Injector injector, PrintWriter printWriter) {
            printWriter.print("Shutdown request from ");
            printWriter.print(getOrigin());
            if (mReason != null) {
@@ -200,12 +202,12 @@ public final class ShutdownCheckPoints {
            printWriter.print(" at ");
            printWriter.print(DATE_FORMAT.format(new Date(mTimestamp)));
            printWriter.println(" (epoch=" + mTimestamp + ")");
            dumpDetails(printWriter);
            dumpDetails(injector, printWriter);
        }

        abstract String getOrigin();

        abstract void dumpDetails(PrintWriter printWriter);
        abstract void dumpDetails(Injector injector, PrintWriter printWriter);
    }

    /** Representation of a shutdown call from the system server, with stack trace. */
@@ -213,8 +215,8 @@ public final class ShutdownCheckPoints {

        private final StackTraceElement[] mStackTraceElements;

        SystemServerCheckPoint(Injector injector, @Nullable String reason) {
            super(injector, reason);
        SystemServerCheckPoint(long timestamp, @Nullable String reason) {
            super(timestamp, reason);
            mStackTraceElements = Thread.currentThread().getStackTrace();
        }

@@ -224,14 +226,14 @@ public final class ShutdownCheckPoints {
        }

        @Override
        void dumpDetails(PrintWriter printWriter) {
            String methodName = getMethodName();
        void dumpDetails(Injector injector, PrintWriter printWriter) {
            String methodName = findMethodName();
            printWriter.println(methodName == null ? "Failed to get method name" : methodName);
            printStackTrace(printWriter);
        }

        @Nullable
        String getMethodName() {
        String findMethodName() {
            int idx = findCallSiteIndex();
            if (idx < mStackTraceElements.length) {
                StackTraceElement element = mStackTraceElements[idx];
@@ -241,7 +243,7 @@ public final class ShutdownCheckPoints {
        }

        void printStackTrace(PrintWriter printWriter) {
            // Skip the call site line, as it's already considered with getMethodName.
            // Skip the call site line, as it's already considered with findMethodName.
            for (int i = findCallSiteIndex() + 1; i < mStackTraceElements.length; i++) {
                printWriter.print(" at ");
                printWriter.println(mStackTraceElements[i]);
@@ -268,12 +270,10 @@ public final class ShutdownCheckPoints {
    /** Representation of a shutdown call to {@link android.os.Binder}, with caller process id. */
    private static class BinderCheckPoint extends SystemServerCheckPoint {
        private final int mCallerProcessId;
        private final IActivityManager mActivityManager;

        BinderCheckPoint(Injector injector, int callerProcessId, @Nullable String reason) {
            super(injector, reason);
        BinderCheckPoint(long timestamp, int callerProcessId, @Nullable String reason) {
            super(timestamp, reason);
            mCallerProcessId = callerProcessId;
            mActivityManager = injector.activityManager();
        }

        @Override
@@ -282,26 +282,33 @@ public final class ShutdownCheckPoints {
        }

        @Override
        void dumpDetails(PrintWriter printWriter) {
            String methodName = getMethodName();
        void dumpDetails(Injector injector, PrintWriter printWriter) {
            String methodName = findMethodName();
            printWriter.println(methodName == null ? "Failed to get method name" : methodName);

            String processName = getProcessName();
            String processName = findProcessName(injector.activityManager());
            printWriter.print("From process ");
            printWriter.print(processName == null ? "?" : processName);
            printWriter.println(" (pid=" + mCallerProcessId + ")");
        }

        @Nullable
        String getProcessName() {
        private String findProcessName(@Nullable IActivityManager activityManager) {
            try {
                List<ActivityManager.RunningAppProcessInfo> runningProcesses =
                        mActivityManager.getRunningAppProcesses();
                List<ActivityManager.RunningAppProcessInfo> runningProcesses = null;
                if (activityManager != null) {
                    runningProcesses = activityManager.getRunningAppProcesses();
                } else {
                    Slog.v(TAG, "No ActivityManager to find name of process with pid="
                        + mCallerProcessId);
                }
                if (runningProcesses != null) {
                    for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
                        if (processInfo.pid == mCallerProcessId) {
                            return processInfo.processName;
                        }
                    }
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to get running app processes from ActivityManager", e);
            }
@@ -315,8 +322,8 @@ public final class ShutdownCheckPoints {
        private final String mPackageName;

        IntentCheckPoint(
                Injector injector, String intentName, String packageName, @Nullable String reason) {
            super(injector, reason);
                long timestamp, String intentName, String packageName, @Nullable String reason) {
            super(timestamp, reason);
            mIntentName = intentName;
            mPackageName = packageName;
        }
@@ -327,7 +334,7 @@ public final class ShutdownCheckPoints {
        }

        @Override
        void dumpDetails(PrintWriter printWriter) {
        void dumpDetails(Injector injector, PrintWriter printWriter) {
            printWriter.print("Intent: ");
            printWriter.println(mIntentName);
            printWriter.print("Package: ");
+27 −3
Original line number Diff line number Diff line
@@ -103,21 +103,45 @@ public class ShutdownCheckPointsTest {
    }

    @Test
    public void testCallerProcessBinderEntry() throws RemoteException {
    public void testCallerProcessBinderEntries() throws RemoteException {
        List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = new ArrayList<>();
        runningAppProcessInfos.add(
                new ActivityManager.RunningAppProcessInfo("process_name", 1, new String[0]));
        when(mActivityManager.getRunningAppProcesses()).thenReturn(runningAppProcessInfos);

        mTestInjector.setCurrentTime(1000);
        // Matching pid in getRunningAppProcesses
        mInstance.recordCheckPointInternal(1, "reason1");
        // Missing pid in getRunningAppProcesses
        mInstance.recordCheckPointInternal(2, "reason2");

        assertEquals(
                "Shutdown request from BINDER for reason reason1 "
                        + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
                        + "com.android.server.power.ShutdownCheckPointsTest"
                        + ".testCallerProcessBinderEntry\n"
                        + "From process process_name (pid=1)\n\n",
                        + ".testCallerProcessBinderEntries\n"
                        + "From process process_name (pid=1)\n\n"
                        + "Shutdown request from BINDER for reason reason2 "
                        + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
                        + "com.android.server.power.ShutdownCheckPointsTest"
                        + ".testCallerProcessBinderEntries\n"
                        + "From process ? (pid=2)\n\n",
                dumpToString());
    }

    @Test
    public void testNullCallerProcessBinderEntries() throws RemoteException {
        when(mActivityManager.getRunningAppProcesses()).thenReturn(null);

        mTestInjector.setCurrentTime(1000);
        mInstance.recordCheckPointInternal(1, "reason1");

        assertEquals(
                "Shutdown request from BINDER for reason reason1 "
                        + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
                        + "com.android.server.power.ShutdownCheckPointsTest"
                        + ".testNullCallerProcessBinderEntries\n"
                        + "From process ? (pid=1)\n\n",
                dumpToString());
    }