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

Commit 0afc60f7 authored by Yisroel Forta's avatar Yisroel Forta
Browse files

Add AppStartInfo object handling

Adds tracker that handles objects (recording, persistence, access) and hooks it up.

Test: make, flash on device
adb shell dumpsys activity start-info [package-name]

Bug: 247814855
Change-Id: Ie9face4b6e5be1a9c08f7a4ceaf52b9df6516a0f
parent a452e0bd
Loading
Loading
Loading
Loading
+106 −1
Original line number Original line Diff line number Diff line
@@ -27,7 +27,15 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArrayMap;

import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
import android.util.proto.WireTypeMismatchException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
@@ -608,6 +616,103 @@ public final class ApplicationStartInfo implements Parcelable {
                }
                }
            };
            };


    /**
     * Write to a protocol buffer output stream. Protocol buffer message definition at {@link
     * android.app.ApplicationStartInfoProto}
     *
     * @param proto Stream to write the ApplicationStartInfo object to.
     * @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
     * @hide
     */
    public void writeToProto(ProtoOutputStream proto, long fieldId) throws IOException {
        final long token = proto.start(fieldId);
        proto.write(ApplicationStartInfoProto.PID, mPid);
        proto.write(ApplicationStartInfoProto.REAL_UID, mRealUid);
        proto.write(ApplicationStartInfoProto.PACKAGE_UID, mPackageUid);
        proto.write(ApplicationStartInfoProto.DEFINING_UID, mDefiningUid);
        proto.write(ApplicationStartInfoProto.PROCESS_NAME, mProcessName);
        proto.write(ApplicationStartInfoProto.STARTUP_STATE, mStartupState);
        proto.write(ApplicationStartInfoProto.REASON, mReason);
        if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
            ByteArrayOutputStream timestampsBytes = new ByteArrayOutputStream();
            ObjectOutputStream timestampsOut = new ObjectOutputStream(timestampsBytes);
            timestampsOut.writeObject(mStartupTimestampsNs);
            proto.write(ApplicationStartInfoProto.STARTUP_TIMESTAMPS,
                    timestampsBytes.toByteArray());
        }
        proto.write(ApplicationStartInfoProto.START_TYPE, mStartType);
        if (mStartIntent != null) {
            Parcel parcel = Parcel.obtain();
            mStartIntent.writeToParcel(parcel, 0);
            proto.write(ApplicationStartInfoProto.START_INTENT, parcel.marshall());
            parcel.recycle();
        }
        proto.write(ApplicationStartInfoProto.LAUNCH_MODE, mLaunchMode);
        proto.end(token);
    }

    /**
     * Read from a protocol buffer input stream. Protocol buffer message definition at {@link
     * android.app.ApplicationStartInfoProto}
     *
     * @param proto Stream to read the ApplicationStartInfo object from.
     * @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
     * @hide
     */
    public void readFromProto(ProtoInputStream proto, long fieldId)
            throws IOException, WireTypeMismatchException, ClassNotFoundException {
        final long token = proto.start(fieldId);
        while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
            switch (proto.getFieldNumber()) {
                case (int) ApplicationStartInfoProto.PID:
                    mPid = proto.readInt(ApplicationStartInfoProto.PID);
                    break;
                case (int) ApplicationStartInfoProto.REAL_UID:
                    mRealUid = proto.readInt(ApplicationStartInfoProto.REAL_UID);
                    break;
                case (int) ApplicationStartInfoProto.PACKAGE_UID:
                    mPackageUid = proto.readInt(ApplicationStartInfoProto.PACKAGE_UID);
                    break;
                case (int) ApplicationStartInfoProto.DEFINING_UID:
                    mDefiningUid = proto.readInt(ApplicationStartInfoProto.DEFINING_UID);
                    break;
                case (int) ApplicationStartInfoProto.PROCESS_NAME:
                    mProcessName = intern(proto.readString(ApplicationStartInfoProto.PROCESS_NAME));
                    break;
                case (int) ApplicationStartInfoProto.STARTUP_STATE:
                    mStartupState = proto.readInt(ApplicationStartInfoProto.STARTUP_STATE);
                    break;
                case (int) ApplicationStartInfoProto.REASON:
                    mReason = proto.readInt(ApplicationStartInfoProto.REASON);
                    break;
                case (int) ApplicationStartInfoProto.STARTUP_TIMESTAMPS:
                    ByteArrayInputStream timestampsBytes = new ByteArrayInputStream(proto.readBytes(
                            ApplicationStartInfoProto.STARTUP_TIMESTAMPS));
                    ObjectInputStream timestampsIn = new ObjectInputStream(timestampsBytes);
                    mStartupTimestampsNs = (ArrayMap<Integer, Long>) timestampsIn.readObject();
                    break;
                case (int) ApplicationStartInfoProto.START_TYPE:
                    mStartType = proto.readInt(ApplicationStartInfoProto.START_TYPE);
                    break;
                case (int) ApplicationStartInfoProto.START_INTENT:
                    byte[] startIntentBytes = proto.readBytes(
                        ApplicationStartInfoProto.START_INTENT);
                    if (startIntentBytes.length > 0) {
                        Parcel parcel = Parcel.obtain();
                        parcel.unmarshall(startIntentBytes, 0, startIntentBytes.length);
                        parcel.setDataPosition(0);
                        mStartIntent = Intent.CREATOR.createFromParcel(parcel);
                        parcel.recycle();
                    }
                    break;
                case (int) ApplicationStartInfoProto.LAUNCH_MODE:
                    mLaunchMode = proto.readInt(ApplicationStartInfoProto.LAUNCH_MODE);
                    break;
            }
        }
        proto.end(token);
    }

    /** @hide */
    /** @hide */
    public void dump(@NonNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix,
    public void dump(@NonNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix,
            @NonNull SimpleDateFormat sdf) {
            @NonNull SimpleDateFormat sdf) {
+42 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

syntax = "proto2";
option java_multiple_files = true;

package android.app;

import "frameworks/base/core/proto/android/privacy.proto";
import "frameworks/proto_logging/stats/enums/app/enums.proto";

/**
 * An android.app.ApplicationStartInfo object.
 */
message ApplicationStartInfoProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional int32 pid = 1;
    optional int32 real_uid = 2;
    optional int32 package_uid = 3;
    optional int32 defining_uid = 4;
    optional string process_name = 5;
    optional AppStartStartupState startup_state = 6;
    optional AppStartReasonCode reason = 7;
    optional bytes startup_timestamps = 8;
    optional AppStartStartType start_type = 9;
    optional bytes start_intent = 10;
    optional AppStartLaunchMode launch_mode = 11;
}
+21 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ package com.android.server.am;


import "frameworks/base/core/proto/android/app/activitymanager.proto";
import "frameworks/base/core/proto/android/app/activitymanager.proto";
import "frameworks/base/core/proto/android/app/appexitinfo.proto";
import "frameworks/base/core/proto/android/app/appexitinfo.proto";
import "frameworks/base/core/proto/android/app/appstartinfo.proto";
import "frameworks/base/core/proto/android/app/notification.proto";
import "frameworks/base/core/proto/android/app/notification.proto";
import "frameworks/base/core/proto/android/app/profilerinfo.proto";
import "frameworks/base/core/proto/android/app/profilerinfo.proto";
import "frameworks/base/core/proto/android/content/component_name.proto";
import "frameworks/base/core/proto/android/content/component_name.proto";
@@ -1041,3 +1042,23 @@ message AppsExitInfoProto {
    }
    }
    repeated Package packages = 2;
    repeated Package packages = 2;
}
}

// sync with com.android.server.am.am.ProcessList.java
message AppsStartInfoProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional int64 last_update_timestamp = 1;
    message Package {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional string package_name = 1;
        message User {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional int32 uid = 1;
            repeated .android.app.ApplicationStartInfoProto app_start_info = 2;
        }
        repeated User users = 2;
    }
    repeated Package packages = 2;
}
+38 −1
Original line number Original line Diff line number Diff line
@@ -9638,9 +9638,29 @@ public class ActivityManagerService extends IActivityManager.Stub
    public ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(
    public ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(
            String packageName, int maxNum, int userId) {
            String packageName, int maxNum, int userId) {
        enforceNotIsolatedCaller("getHistoricalProcessStartReasons");
        enforceNotIsolatedCaller("getHistoricalProcessStartReasons");
        // For the simplification, we don't support USER_ALL nor USER_CURRENT here.
        if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_CURRENT) {
            throw new IllegalArgumentException("Unsupported userId");
        }
        final ArrayList<ApplicationStartInfo> results = new ArrayList<ApplicationStartInfo>();
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        mUserController.handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_NON_FULL,
                "getHistoricalProcessStartReasons", null);
        final ArrayList<ApplicationStartInfo> results = new ArrayList<ApplicationStartInfo>();
        if (!TextUtils.isEmpty(packageName)) {
            final int uid = enforceDumpPermissionForPackage(packageName, userId, callingUid,
                        "getHistoricalProcessStartReasons");
            if (uid != INVALID_UID) {
                mProcessList.mAppStartInfoTracker.getStartInfo(
                        packageName, userId, callingPid, maxNum, results);
            }
        } else {
            // If no package name is given, use the caller's uid as the filter uid.
            mProcessList.mAppStartInfoTracker.getStartInfo(
                    packageName, callingUid, callingPid, maxNum, results);
        }
        return new ParceledListSlice<ApplicationStartInfo>(results);
        return new ParceledListSlice<ApplicationStartInfo>(results);
    }
    }
@@ -9649,6 +9669,14 @@ public class ActivityManagerService extends IActivityManager.Stub
    public void setApplicationStartInfoCompleteListener(
    public void setApplicationStartInfoCompleteListener(
            IApplicationStartInfoCompleteListener listener, int userId) {
            IApplicationStartInfoCompleteListener listener, int userId) {
        enforceNotIsolatedCaller("setApplicationStartInfoCompleteListener");
        enforceNotIsolatedCaller("setApplicationStartInfoCompleteListener");
        // For the simplification, we don't support USER_ALL nor USER_CURRENT here.
        if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_CURRENT) {
            throw new IllegalArgumentException("Unsupported userId");
        }
        final int callingUid = Binder.getCallingUid();
        mProcessList.mAppStartInfoTracker.addStartInfoCompleteListener(listener, callingUid);
    }
    }
@@ -9662,6 +9690,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        }
        final int callingUid = Binder.getCallingUid();
        final int callingUid = Binder.getCallingUid();
        mProcessList.mAppStartInfoTracker.clearStartInfoCompleteListener(callingUid, true);
    }
    }
    @Override
    @Override
@@ -9962,6 +9991,8 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
            }
            pw.println();
            pw.println();
            if (dumpAll) {
            if (dumpAll) {
                pw.println("-------------------------------------------------------------------------------");
                mProcessList.mAppStartInfoTracker.dumpHistoryProcessStartInfo(pw, dumpPackage);
                pw.println("-------------------------------------------------------------------------------");
                pw.println("-------------------------------------------------------------------------------");
                mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
                mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
            }
            }
@@ -10359,6 +10390,12 @@ public class ActivityManagerService extends IActivityManager.Stub
                LockGuard.dump(fd, pw, args);
                LockGuard.dump(fd, pw, args);
            } else if ("users".equals(cmd)) {
            } else if ("users".equals(cmd)) {
                dumpUsers(pw);
                dumpUsers(pw);
            } else if ("start-info".equals(cmd)) {
                if (opti < args.length) {
                    dumpPackage = args[opti];
                    opti++;
                }
                mProcessList.mAppStartInfoTracker.dumpHistoryProcessStartInfo(pw, dumpPackage);
            } else if ("exit-info".equals(cmd)) {
            } else if ("exit-info".equals(cmd)) {
                if (opti < args.length) {
                if (opti < args.length) {
                    dumpPackage = args[opti];
                    dumpPackage = args[opti];
+30 −0
Original line number Original line Diff line number Diff line
@@ -272,6 +272,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    return runSetWatchHeap(pw);
                    return runSetWatchHeap(pw);
                case "clear-watch-heap":
                case "clear-watch-heap":
                    return runClearWatchHeap(pw);
                    return runClearWatchHeap(pw);
                case "clear-start-info":
                    return runClearStartInfo(pw);
                case "clear-exit-info":
                case "clear-exit-info":
                    return runClearExitInfo(pw);
                    return runClearExitInfo(pw);
                case "bug-report":
                case "bug-report":
@@ -1339,6 +1341,31 @@ final class ActivityManagerShellCommand extends ShellCommand {
        return 0;
        return 0;
    }
    }


    int runClearStartInfo(PrintWriter pw) throws RemoteException {
        mInternal.enforceCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
                "runClearStartInfo()");
        String opt;
        int userId = UserHandle.USER_CURRENT;
        String packageName = null;
        while ((opt = getNextOption()) != null) {
            if (opt.equals("--user")) {
                userId = UserHandle.parseUserArg(getNextArgRequired());
            } else {
                packageName = opt;
            }
        }
        if (userId == UserHandle.USER_CURRENT) {
            UserInfo user = mInterface.getCurrentUser();
            if (user == null) {
                return -1;
            }
            userId = user.id;
        }
        mInternal.mProcessList.mAppStartInfoTracker
                .clearHistoryProcessStartInfo(packageName, userId);
        return 0;
    }

    int runClearExitInfo(PrintWriter pw) throws RemoteException {
    int runClearExitInfo(PrintWriter pw) throws RemoteException {
        mInternal.enforceCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
        mInternal.enforceCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
                "runClearExitInfo()");
                "runClearExitInfo()");
@@ -4090,6 +4117,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("    s[ervices] [COMP_SPEC ...]: service state");
            pw.println("    s[ervices] [COMP_SPEC ...]: service state");
            pw.println("    allowed-associations: current package association restrictions");
            pw.println("    allowed-associations: current package association restrictions");
            pw.println("    as[sociations]: tracked app associations");
            pw.println("    as[sociations]: tracked app associations");
            pw.println("    start-info [PACKAGE_NAME]: historical process start information");
            pw.println("    exit-info [PACKAGE_NAME]: historical process exit information");
            pw.println("    exit-info [PACKAGE_NAME]: historical process exit information");
            pw.println("    lmk: stats on low memory killer");
            pw.println("    lmk: stats on low memory killer");
            pw.println("    lru: raw LRU process list");
            pw.println("    lru: raw LRU process list");
@@ -4265,6 +4293,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("      above <HEAP-LIMIT> then a heap dump is collected for the user to report.");
            pw.println("      above <HEAP-LIMIT> then a heap dump is collected for the user to report.");
            pw.println("  clear-watch-heap");
            pw.println("  clear-watch-heap");
            pw.println("      Clear the previously set-watch-heap.");
            pw.println("      Clear the previously set-watch-heap.");
            pw.println("  clear-start-info [--user <USER_ID> | all | current] [package]");
            pw.println("      Clear the process start-info for given package");
            pw.println("  clear-exit-info [--user <USER_ID> | all | current] [package]");
            pw.println("  clear-exit-info [--user <USER_ID> | all | current] [package]");
            pw.println("      Clear the process exit-info for given package");
            pw.println("      Clear the process exit-info for given package");
            pw.println("  bug-report [--progress | --telephony]");
            pw.println("  bug-report [--progress | --telephony]");
Loading