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

Commit 3d4b7c09 authored by Yisroel Forta's avatar Yisroel Forta Committed by Android (Google) Code Review
Browse files

Merge "AppStartInfo Unit tests" into main

parents e2ffdc6e c58b6e84
Loading
Loading
Loading
Loading
+103 −2
Original line number Diff line number Diff line
@@ -26,11 +26,19 @@ import android.icu.text.SimpleDateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Xml;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
import android.util.proto.WireTypeMismatchException;

import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;

import org.xmlpull.v1.XmlPullParserException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -40,6 +48,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import java.util.Objects;

/**
 * Describes information related to an application process's startup.
@@ -214,6 +223,11 @@ public final class ApplicationStartInfo implements Parcelable {
     */
    private int mDefiningUid;

    /**
     * @see #getPackageName
     */
    private String mPackageName;

    /**
     * @see #getProcessName
     */
@@ -348,6 +362,14 @@ public final class ApplicationStartInfo implements Parcelable {
        mDefiningUid = uid;
    }

    /**
     * @see #getPackageName
     * @hide
     */
    public void setPackageName(final String packageName) {
        mPackageName = intern(packageName);
    }

    /**
     * @see #getProcessName
     * @hide
@@ -460,6 +482,15 @@ public final class ApplicationStartInfo implements Parcelable {
        return mDefiningUid;
    }

    /**
     * Name of first package running in this process;
     *
     * @hide
     */
    public String getPackageName() {
        return mPackageName;
    }

    /**
     * The actual process name it was running with.
     *
@@ -555,6 +586,7 @@ public final class ApplicationStartInfo implements Parcelable {
        dest.writeInt(mRealUid);
        dest.writeInt(mPackageUid);
        dest.writeInt(mDefiningUid);
        dest.writeString(mPackageName);
        dest.writeString(mProcessName);
        dest.writeInt(mReason);
        dest.writeInt(mStartupTimestampsNs == null ? 0 : mStartupTimestampsNs.size());
@@ -579,6 +611,7 @@ public final class ApplicationStartInfo implements Parcelable {
        mRealUid = other.mRealUid;
        mPackageUid = other.mPackageUid;
        mDefiningUid = other.mDefiningUid;
        mPackageName = other.mPackageName;
        mProcessName = other.mProcessName;
        mReason = other.mReason;
        mStartupTimestampsNs = other.mStartupTimestampsNs;
@@ -593,6 +626,7 @@ public final class ApplicationStartInfo implements Parcelable {
        mRealUid = in.readInt();
        mPackageUid = in.readInt();
        mDefiningUid = in.readInt();
        mPackageName = intern(in.readString());
        mProcessName = intern(in.readString());
        mReason = in.readInt();
        int starupTimestampCount = in.readInt();
@@ -624,6 +658,11 @@ public final class ApplicationStartInfo implements Parcelable {
                }
            };

    private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS = "timestamps";
    private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP = "timestamp";
    private static final String PROTO_SERIALIZER_ATTRIBUTE_KEY = "key";
    private static final String PROTO_SERIALIZER_ATTRIBUTE_TS = "ts";

    /**
     * Write to a protocol buffer output stream. Protocol buffer message definition at {@link
     * android.app.ApplicationStartInfoProto}
@@ -644,9 +683,22 @@ public final class ApplicationStartInfo implements Parcelable {
        if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
            ByteArrayOutputStream timestampsBytes = new ByteArrayOutputStream();
            ObjectOutputStream timestampsOut = new ObjectOutputStream(timestampsBytes);
            timestampsOut.writeObject(mStartupTimestampsNs);
            TypedXmlSerializer serializer = Xml.resolveSerializer(timestampsOut);
            serializer.startDocument(null, true);
            serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
            for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
                serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
                serializer.attributeInt(null, PROTO_SERIALIZER_ATTRIBUTE_KEY,
                        mStartupTimestampsNs.keyAt(i));
                serializer.attributeLong(null, PROTO_SERIALIZER_ATTRIBUTE_TS,
                        mStartupTimestampsNs.valueAt(i));
                serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
            }
            serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
            serializer.endDocument();
            proto.write(ApplicationStartInfoProto.STARTUP_TIMESTAMPS,
                    timestampsBytes.toByteArray());
            timestampsOut.close();
        }
        proto.write(ApplicationStartInfoProto.START_TYPE, mStartType);
        if (mStartIntent != null) {
@@ -697,7 +749,24 @@ public final class ApplicationStartInfo implements Parcelable {
                    ByteArrayInputStream timestampsBytes = new ByteArrayInputStream(proto.readBytes(
                            ApplicationStartInfoProto.STARTUP_TIMESTAMPS));
                    ObjectInputStream timestampsIn = new ObjectInputStream(timestampsBytes);
                    mStartupTimestampsNs = (ArrayMap<Integer, Long>) timestampsIn.readObject();
                    mStartupTimestampsNs = new ArrayMap<Integer, Long>();
                    try {
                        TypedXmlPullParser parser = Xml.resolvePullParser(timestampsIn);
                        XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
                        int depth = parser.getDepth();
                        while (XmlUtils.nextElementWithin(parser, depth)) {
                            if (PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP.equals(parser.getName())) {
                                int key = parser.getAttributeInt(null,
                                        PROTO_SERIALIZER_ATTRIBUTE_KEY);
                                long ts = parser.getAttributeLong(null,
                                        PROTO_SERIALIZER_ATTRIBUTE_TS);
                                mStartupTimestampsNs.put(key, ts);
                            }
                        }
                    } catch (XmlPullParserException e) {
                        // Timestamps lost
                    }
                    timestampsIn.close();
                    break;
                case (int) ApplicationStartInfoProto.START_TYPE:
                    mStartType = proto.readInt(ApplicationStartInfoProto.START_TYPE);
@@ -734,6 +803,7 @@ public final class ApplicationStartInfo implements Parcelable {
                .append(" definingUid=").append(mDefiningUid)
                .append(" user=").append(UserHandle.getUserId(mPackageUid))
                .append('\n')
                .append(" package=").append(mPackageName)
                .append(" process=").append(mProcessName)
                .append(" startupState=").append(mStartupState)
                .append(" reason=").append(reasonToString(mReason))
@@ -782,4 +852,35 @@ public final class ApplicationStartInfo implements Parcelable {
            default -> "";
        };
    }

    /** @hide */
    @Override
    public boolean equals(@Nullable Object other) {
        if (other == null || !(other instanceof ApplicationStartInfo)) {
            return false;
        }
        final ApplicationStartInfo o = (ApplicationStartInfo) other;
        return mPid == o.mPid && mRealUid == o.mRealUid && mPackageUid == o.mPackageUid
            && mDefiningUid == o.mDefiningUid && mReason == o.mReason
            && mStartupState == o.mStartupState && mStartType == o.mStartType
            && mLaunchMode == o.mLaunchMode && TextUtils.equals(mProcessName, o.mProcessName)
            && timestampsEquals(o);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mPid, mRealUid, mPackageUid, mDefiningUid, mReason, mStartupState,
                mStartType, mLaunchMode, mProcessName,
                mStartupTimestampsNs);
    }

    private boolean timestampsEquals(@NonNull ApplicationStartInfo other) {
        if (mStartupTimestampsNs == null && other.mStartupTimestampsNs == null) {
            return true;
        }
        if (mStartupTimestampsNs == null || other.mStartupTimestampsNs == null) {
            return false;
        }
        return mStartupTimestampsNs.equals(other.mStartupTimestampsNs);
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -5400,13 +5400,13 @@ public final class ActiveServices {
                return msg;
            }
            mAm.mProcessList.getAppStartInfoTracker().handleProcessServiceStart(startTimeNs, app, r,
                    hostingRecord, true);
                    true);
            if (isolated) {
                r.isolationHostProc = app;
            }
        } else {
            mAm.mProcessList.getAppStartInfoTracker().handleProcessServiceStart(startTimeNs, app, r,
                    hostingRecord, false);
                    false);
        }

        if (r.fgRequired) {
+27 −15
Original line number Diff line number Diff line
@@ -81,18 +81,18 @@ public final class AppStartInfoTracker {
    private static final int FOREACH_ACTION_REMOVE_ITEM = 1;
    private static final int FOREACH_ACTION_STOP_ITERATION = 2;

    private static final int APP_START_INFO_HISTORY_LIST_SIZE = 16;
    @VisibleForTesting static final int APP_START_INFO_HISTORY_LIST_SIZE = 16;

    @VisibleForTesting static final String APP_START_STORE_DIR = "procstartstore";

    @VisibleForTesting static final String APP_START_INFO_FILE = "procstartinfo";

    private final Object mLock = new Object();
    @VisibleForTesting final Object mLock = new Object();

    private boolean mEnabled = false;
    @VisibleForTesting boolean mEnabled = false;

    /** Initialized in {@link #init} and read-only after that. */
    private ActivityManagerService mService;
    @VisibleForTesting ActivityManagerService mService;

    /** Initialized in {@link #init} and read-only after that. */
    private Handler mHandler;
@@ -112,7 +112,7 @@ public final class AppStartInfoTracker {
     *
     * <p>Initialized in {@link #init} and read-only after that. No lock is needed.
     */
    private int mAppStartInfoHistoryListSize;
    @VisibleForTesting int mAppStartInfoHistoryListSize;

    @GuardedBy("mLock")
    private final ProcessMap<AppStartInfoContainer> mData;
@@ -146,7 +146,8 @@ public final class AppStartInfoTracker {
     * Key is timestamp of launch from {@link #ActivityMetricsLaunchObserver}.
     */
    @GuardedBy("mLock")
    private ArrayMap<Long, ApplicationStartInfo> mInProgRecords = new ArrayMap<>();
    @VisibleForTesting
    final ArrayMap<Long, ApplicationStartInfo> mInProgRecords = new ArrayMap<>();

    AppStartInfoTracker() {
        mCallbacks = new SparseArray<>();
@@ -229,7 +230,7 @@ public final class AppStartInfoTracker {
                ApplicationStartInfo info = mInProgRecords.get(id);
                info.setStartType((int) temperature);
                addBaseFieldsFromProcessRecord(info, app);
                addStartInfoLocked(info);
                mInProgRecords.put(id, addStartInfoLocked(info));
            } else {
                mInProgRecords.remove(id);
            }
@@ -262,6 +263,7 @@ public final class AppStartInfoTracker {
            ApplicationStartInfo info = mInProgRecords.get(id);
            info.setStartupState(ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN);
            info.setLaunchMode(launchMode);
            checkCompletenessAndCallback(info);
        }
    }

@@ -281,7 +283,7 @@ public final class AppStartInfoTracker {
    }

    public void handleProcessServiceStart(long startTimeNs, ProcessRecord app,
                ServiceRecord serviceRecord, HostingRecord hostingRecord, boolean cold) {
                ServiceRecord serviceRecord, boolean cold) {
        synchronized (mLock) {
            if (!mEnabled) {
                return;
@@ -297,7 +299,9 @@ public final class AppStartInfoTracker {
                    && serviceRecord.permission.contains("android.permission.BIND_JOB_SERVICE")
                    ? ApplicationStartInfo.START_REASON_JOB
                    : ApplicationStartInfo.START_REASON_SERVICE);
            if (serviceRecord.intent != null) {
                start.setIntent(serviceRecord.intent.getIntent());
            }
            addStartInfoLocked(start);
        }
    }
@@ -378,6 +382,7 @@ public final class AppStartInfoTracker {
        start.setPackageUid(app.info.uid);
        start.setDefiningUid(definingUid > 0 ? definingUid : app.info.uid);
        start.setProcessName(app.processName);
        start.setPackageName(app.info.packageName);
    }

    void reportApplicationOnCreateTimeNanos(ProcessRecord app, long timeNs) {
@@ -419,12 +424,12 @@ public final class AppStartInfoTracker {
    }

    private void addTimestampToStart(ProcessRecord app, long timeNs, int key) {
        addTimestampToStart(app.processName, app.uid, timeNs, key);
        addTimestampToStart(app.info.packageName, app.uid, timeNs, key);
    }

    private void addTimestampToStart(String processName, int uid, long timeNs, int key) {
    private void addTimestampToStart(String packageName, int uid, long timeNs, int key) {
        synchronized (mLock) {
            AppStartInfoContainer container = mData.get(processName, uid);
            AppStartInfoContainer container = mData.get(packageName, uid);
            if (container == null) {
                // Record was not created, discard new data.
                return;
@@ -443,11 +448,11 @@ public final class AppStartInfoTracker {

        final ApplicationStartInfo info = new ApplicationStartInfo(raw);

        AppStartInfoContainer container = mData.get(raw.getProcessName(), raw.getRealUid());
        AppStartInfoContainer container = mData.get(raw.getPackageName(), raw.getRealUid());
        if (container == null) {
            container = new AppStartInfoContainer(mAppStartInfoHistoryListSize);
            container.mUid = info.getRealUid();
            mData.put(raw.getProcessName(), raw.getRealUid(), container);
            mData.put(raw.getPackageName(), raw.getRealUid(), container);
        }
        container.addStartInfoLocked(info);

@@ -486,6 +491,9 @@ public final class AppStartInfoTracker {
        if (!mEnabled) {
            return;
        }
        if (maxNum == 0) {
            maxNum = APP_START_INFO_HISTORY_LIST_SIZE;
        }
        final long identity = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
@@ -891,6 +899,7 @@ public final class AppStartInfoTracker {
                mProcStartInfoFile.delete();
            }
            mData.getMap().clear();
            mInProgRecords.clear();
        }
    }

@@ -960,6 +969,10 @@ public final class AppStartInfoTracker {

    /** Convenience method to obtain timestamp of beginning of start.*/
    private static long getStartTimestamp(ApplicationStartInfo startInfo) {
        if (startInfo.getStartupTimestamps() == null
                    || !startInfo.getStartupTimestamps().containsKey(START_TIMESTAMP_LAUNCH)) {
            return -1;
        }
        return startInfo.getStartupTimestamps().get(START_TIMESTAMP_LAUNCH);
    }

@@ -997,7 +1010,6 @@ public final class AppStartInfoTracker {
                if (oldestIndex >= 0) {
                    mInfos.remove(oldestIndex);
                }
                mInfos.remove(0);
            }
            mInfos.add(info);
            Collections.sort(mInfos, (a, b) ->
+587 −0

File added.

Preview size limit exceeded, changes collapsed.