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

Commit cc1bcf90 authored by Riddle Hsu's avatar Riddle Hsu Committed by Automerger Merge Worker
Browse files

Merge "Reduce overhead of activity launch observer" into tm-dev am: e0d21194

parents fbe145bc e0d21194
Loading
Loading
Loading
Loading
+1 −22
Original line number Diff line number Diff line
@@ -1024,30 +1024,9 @@ public class ActivityManagerService extends IActivityManager.Stub
    private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
            new ActivityMetricsLaunchObserver() {
        @Override
        public void onActivityLaunched(byte[] activity, int temperature) {
        public void onActivityLaunched(long id, ComponentName name, int temperature) {
            mAppProfiler.onActivityLaunched();
        }
        // The other observer methods are unused
        @Override
        public void onIntentStarted(Intent intent, long timestampNs) {
        }
        @Override
        public void onIntentFailed() {
        }
        @Override
        public void onActivityLaunchCancelled(byte[] abortingActivity) {
        }
        @Override
        public void onActivityLaunchFinished(byte[] finalActivity, long timestampNs) {
        }
        @Override
        public void onReportFullyDrawn(byte[] finalActivity, long timestampNs) {
        }
    };
    private volatile boolean mBinderTransactionTrackingEnabled = false;
+35 −46
Original line number Diff line number Diff line
@@ -18,17 +18,19 @@ package com.android.server.wm;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Observe activity manager launch sequences.
 * Observe activity launch sequences.
 *
 * The activity manager can have at most 1 concurrent launch sequences. Calls to this interface
 * are ordered by a happens-before relation for each defined state transition (see below).
 * Multiple calls to the callback methods can occur without first terminating the current launch
 * sequence because activity can be launched concurrently. So the implementation should associate
 * the corresponding event according to the timestamp from {@link #onIntentStarted} which is also
 * used as the identifier to indicate which launch sequence it belongs to.
 *
 * When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which
 * is communicated by the {@link #onIntentStarted} callback. This is a transient state.
@@ -47,7 +49,7 @@ import java.lang.annotation.RetentionPolicy;
 * Note this transition may not happen if the reportFullyDrawn event is not receivied,
 * in which case {@code FINISHED} is terminal.
 *
 * Note that the {@code ActivityRecordProto} provided as a parameter to some state transitions isn't
 * Note that the {@code ComponentName} provided as a parameter to some state transitions isn't
 * necessarily the same within a single launch sequence: it is only the top-most activity at the
 * time (if any). Trampoline activities coalesce several activity starts into a single launch
 * sequence.
@@ -67,7 +69,7 @@ import java.lang.annotation.RetentionPolicy;
 *        ╚════════════════╝     ╚═══════════════════════════╝     ╚═══════════════════════════╝
 * </pre>
 */
public interface ActivityMetricsLaunchObserver {
public class ActivityMetricsLaunchObserver {
    /**
     * The 'temperature' at which a launch sequence had started.
     *
@@ -98,14 +100,6 @@ public interface ActivityMetricsLaunchObserver {
    /** Hot launch sequence: process reused, activity brought-to-top. */
    public static final int TEMPERATURE_HOT = 3;

    /**
     * Typedef marker that a {@code byte[]} actually contains an
     * <a href="proto/android/server/activitymanagerservice.proto">ActivityRecordProto</a>
     * in the protobuf format.
     */
    @Retention(RetentionPolicy.SOURCE)
    @interface ActivityRecordProto {}

    /**
     * Notifies the observer that a new launch sequence has begun as a result of a new intent.
     *
@@ -113,26 +107,25 @@ public interface ActivityMetricsLaunchObserver {
     * {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to
     * a security error) with {@link #onIntentFailed}.
     *
     * Multiple calls to this method cannot occur without first terminating the current
     * launch sequence.
     * @param timestampNanos The timestamp when receiving the intent. It is also use as an
     *                       identifier for other callback methods to known which launch sequence
     *                       it is associated with.
     */
    public void onIntentStarted(@NonNull Intent intent, long timestampNanos);
    public void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
    }

    /**
     * Notifies the observer that the current launch sequence has failed to launch an activity.
     *
     * This function call terminates the current launch sequence. The next method call, if any,
     * must be {@link #onIntentStarted}.
     * This function call terminates the current launch sequence.
     *
     * Examples of this happening:
     *  - Failure to resolve to an activity
     *  - Calling package did not have the security permissions to call the requested activity
     *  - Resolved activity was already running and only needed to be brought to the top
     *
     * Multiple calls to this method cannot occur without first terminating the current
     * launch sequence.
     */
    public void onIntentFailed();
    public void onIntentFailed(long id) {
    }

    /**
     * Notifies the observer that the current launch sequence had begun starting an activity.
@@ -145,62 +138,58 @@ public interface ActivityMetricsLaunchObserver {
     * necessarily the activity which will be considered as displayed when the activity
     * finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}).
     *
     * Multiple calls to this method cannot occur without first terminating the current
     * launch sequence.
     * @param id The timestamp as an identifier from {@link #onIntentStarted}. It may be a new id
     *           if the launching activity is started from an existing launch sequence (trampoline)
     *           but cannot coalesce to the existing one, e.g. to a different display.
     * @param name The launching activity name.
     */
    public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
                                   @Temperature int temperature);
    public void onActivityLaunched(long id, ComponentName name, @Temperature int temperature) {
    }

    /**
     * Notifies the observer that the current launch sequence has been aborted.
     *
     * This function call terminates the current launch sequence. The next method call, if any,
     * must be {@link #onIntentStarted}.
     * This function call terminates the current launch sequence.
     *
     * This can happen for many reasons, for example the user switches away to another app
     * prior to the launch sequence completing, or the application being killed.
     *
     * Multiple calls to this method cannot occur without first terminating the current
     * launch sequence.
     *
     * @param abortingActivity the last activity that had the top-most window during abort
     *                         (this can be {@code null} in rare situations its unknown).
     * @param id The timestamp as an identifier from {@link #onIntentStarted}.
     *
     * @apiNote The aborting activity isn't necessarily the same as the starting activity;
     *          in the case of a trampoline, multiple activities could've been started
     *          and only the latest activity is reported here.
     */
    public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] abortingActivity);
    public void onActivityLaunchCancelled(long id) {
    }

    /**
     * Notifies the observer that the current launch sequence has been successfully finished.
     *
     * This function call terminates the current launch sequence. The next method call, if any,
     * must be {@link #onIntentStarted}.
     * This function call terminates the current launch sequence.
     *
     * A launch sequence is considered to be successfully finished when a frame is fully
     * drawn for the first time: the top-most activity at the time is what's reported here.
     *
     * @param finalActivity the top-most activity whose windows were first to fully draw
     * @param id The timestamp as an identifier from {@link #onIntentStarted}.
     * @param name The name of drawn activity. It can be different from {@link #onActivityLaunched}
     *             if the transition contains multiple launching activities (e.g. trampoline).
     * @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds.
     *        To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted}
     *        from {@code timestampNanos}.
     *
     * Multiple calls to this method cannot occur without first terminating the current
     * launch sequence.
     *
     * @apiNote The finishing activity isn't necessarily the same as the starting activity;
     *          in the case of a trampoline, multiple activities could've been started
     *          and only the latest activity that was top-most during first-frame drawn
     *          is reported here.
     */
    public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity,
                                         long timestampNanos);
    public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos) {
    }

    /**
     * Notifies the observer that the application self-reported itself as being fully drawn.
     *
     * @param activity the activity that triggers the ReportFullyDrawn event.
     * @param id The timestamp as an identifier from {@link #onIntentStarted}.
     * @param timestampNanos the timestamp of ReportFullyDrawn event in nanoseconds.
     *        To compute the duration, deduct the deduct the timestamp {@link #onIntentStarted}
     *        from {@code timestampNanos}.
@@ -209,7 +198,7 @@ public interface ActivityMetricsLaunchObserver {
     *          It is used as an accurate estimate of meanfully app startup time.
     *          This event may be missing for many apps.
     */
    public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
        long timestampNanos);
    public void onReportFullyDrawn(long id, long timestampNanos) {
    }

}
+12 −38
Original line number Diff line number Diff line
@@ -97,7 +97,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -176,7 +175,6 @@ class ActivityMetricsLogger {
     * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
     */
    private final LaunchObserverRegistryImpl mLaunchObserver;
    @VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
    private final ArrayMap<String, Boolean> mLastHibernationStates = new ArrayMap<>();
    private AppHibernationManagerInternal mAppHibernationManagerInternal;

@@ -675,7 +673,7 @@ class ActivityMetricsLogger {
            launchObserverNotifyActivityLaunched(newInfo);
        } else {
            // As abort for no process switch.
            launchObserverNotifyIntentFailed();
            launchObserverNotifyIntentFailed(newInfo.mTransitionStartTimeNs);
        }
        scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);

@@ -910,7 +908,7 @@ class ActivityMetricsLogger {
        }
        if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
        state.stopTrace(true /* abort */);
        launchObserverNotifyIntentFailed();
        launchObserverNotifyIntentFailed(state.mCurrentTransitionStartTimeNs);
    }

    /** Aborts tracking of current launch metrics. */
@@ -1187,7 +1185,7 @@ class ActivityMetricsLogger {
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Notify reportFullyDrawn event.
        launchObserverNotifyReportFullyDrawn(r, currentTimestampNs);
        launchObserverNotifyReportFullyDrawn(info, currentTimestampNs);

        return infoSnapshot;
    }
@@ -1531,11 +1529,11 @@ class ActivityMetricsLogger {
     * aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
     * intent being delivered to the top running activity.
     */
    private void launchObserverNotifyIntentFailed() {
    private void launchObserverNotifyIntentFailed(long id) {
       Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyIntentFailed");

        mLaunchObserver.onIntentFailed();
        mLaunchObserver.onIntentFailed(id);

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
@@ -1552,8 +1550,8 @@ class ActivityMetricsLogger {
                convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);

        // Beginning a launch is timing sensitive and so should be observed as soon as possible.
        mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.mLastLaunchedActivity),
                temperature);
        mLaunchObserver.onActivityLaunched(info.mTransitionStartTimeNs,
                info.mLastLaunchedActivity.mActivityComponent, temperature);

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
@@ -1561,10 +1559,10 @@ class ActivityMetricsLogger {
    /**
     * Notifies the {@link ActivityMetricsLaunchObserver} the reportFullDrawn event.
     */
    private void launchObserverNotifyReportFullyDrawn(ActivityRecord r, long timestampNs) {
    private void launchObserverNotifyReportFullyDrawn(TransitionInfo info, long timestampNs) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
            "MetricsLogger:launchObserverNotifyReportFullyDrawn");
        mLaunchObserver.onReportFullyDrawn(convertActivityRecordToProto(r), timestampNs);
        mLaunchObserver.onReportFullyDrawn(info.mTransitionStartTimeNs, timestampNs);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

@@ -1576,10 +1574,7 @@ class ActivityMetricsLogger {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyActivityLaunchCancelled");

        final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
                info != null ? convertActivityRecordToProto(info.mLastLaunchedActivity) : null;

        mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);
        mLaunchObserver.onActivityLaunchCancelled(info.mTransitionStartTimeNs);

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
@@ -1592,33 +1587,12 @@ class ActivityMetricsLogger {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyActivityLaunchFinished");

        mLaunchObserver.onActivityLaunchFinished(
                convertActivityRecordToProto(info.mLastLaunchedActivity), timestampNs);
        mLaunchObserver.onActivityLaunchFinished(info.mTransitionStartTimeNs,
                info.mLastLaunchedActivity.mActivityComponent, timestampNs);

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

    @VisibleForTesting
    static @ActivityMetricsLaunchObserver.ActivityRecordProto byte[]
            convertActivityRecordToProto(ActivityRecord record) {
        // May take non-negligible amount of time to convert ActivityRecord into a proto,
        // so track the time.
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:convertActivityRecordToProto");

        // There does not appear to be a way to 'reset' a ProtoOutputBuffer stream,
        // so create a new one every time.
        final ProtoOutputStream protoOutputStream =
                new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
        // Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object).
        record.dumpDebug(protoOutputStream, WindowTraceLogLevel.ALL);
        final byte[] bytes = protoOutputStream.getBytes();

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        return bytes;
    }

    private static @ActivityMetricsLaunchObserver.Temperature int
            convertTransitionTypeToLaunchObserverTemperature(int transitionType) {
        switch (transitionType) {
+26 −46
Original line number Diff line number Diff line
@@ -16,12 +16,11 @@

package com.android.server.wm;

import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import com.android.internal.os.BackgroundThread;
import com.android.internal.util.function.pooled.PooledLambda;

import java.util.ArrayList;
@@ -39,8 +38,8 @@ import java.util.ArrayList;
 *
 * @see ActivityTaskManagerInternal#getLaunchObserverRegistry()
 */
class LaunchObserverRegistryImpl implements
        ActivityMetricsLaunchObserverRegistry, ActivityMetricsLaunchObserver {
class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implements
        ActivityMetricsLaunchObserverRegistry {
    private final ArrayList<ActivityMetricsLaunchObserver> mList = new ArrayList<>();

    /**
@@ -79,45 +78,36 @@ class LaunchObserverRegistryImpl implements
    }

    @Override
    public void onIntentFailed() {
    public void onIntentFailed(long id) {
        mHandler.sendMessage(PooledLambda.obtainMessage(
                LaunchObserverRegistryImpl::handleOnIntentFailed, this));
                LaunchObserverRegistryImpl::handleOnIntentFailed, this, id));
    }

    @Override
    public void onActivityLaunched(
            @ActivityRecordProto byte[] activity,
            int temperature) {
    public void onActivityLaunched(long id, ComponentName name, int temperature) {
        mHandler.sendMessage(PooledLambda.obtainMessage(
                LaunchObserverRegistryImpl::handleOnActivityLaunched,
                this, activity, temperature));
                this, id, name, temperature));
    }

    @Override
    public void onActivityLaunchCancelled(
        @ActivityRecordProto byte[] activity) {
    public void onActivityLaunchCancelled(long id) {
        mHandler.sendMessage(PooledLambda.obtainMessage(
                LaunchObserverRegistryImpl::handleOnActivityLaunchCancelled, this, activity));
                LaunchObserverRegistryImpl::handleOnActivityLaunchCancelled, this, id));
    }

    @Override
    public void onActivityLaunchFinished(
        @ActivityRecordProto byte[] activity,
        long timestampNs) {
    public void onActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
        mHandler.sendMessage(PooledLambda.obtainMessage(
                LaunchObserverRegistryImpl::handleOnActivityLaunchFinished,
            this,
            activity,
            timestampNs));
                this, id, name, timestampNs));
    }

    @Override
    public void onReportFullyDrawn(@ActivityRecordProto byte[] activity, long timestampNs) {
    public void onReportFullyDrawn(long id, long timestampNs) {
        mHandler.sendMessage(PooledLambda.obtainMessage(
                LaunchObserverRegistryImpl::handleOnReportFullyDrawn,
            this,
            activity,
            timestampNs));
                this, id, timestampNs));
    }

    // Use PooledLambda.obtainMessage to invoke below methods. Every method reference must be
@@ -135,53 +125,43 @@ class LaunchObserverRegistryImpl implements
    private void handleOnIntentStarted(Intent intent, long timestampNs) {
        // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
        for (int i = 0; i < mList.size(); i++) {
             ActivityMetricsLaunchObserver o = mList.get(i);
             o.onIntentStarted(intent, timestampNs);
            mList.get(i).onIntentStarted(intent, timestampNs);
        }
    }

    private void handleOnIntentFailed() {
    private void handleOnIntentFailed(long id) {
        // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
        for (int i = 0; i < mList.size(); i++) {
             ActivityMetricsLaunchObserver o = mList.get(i);
             o.onIntentFailed();
            mList.get(i).onIntentFailed(id);
        }
    }

    private void handleOnActivityLaunched(
            @ActivityRecordProto byte[] activity,
    private void handleOnActivityLaunched(long id, ComponentName name,
            @Temperature int temperature) {
        // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
        for (int i = 0; i < mList.size(); i++) {
             ActivityMetricsLaunchObserver o = mList.get(i);
             o.onActivityLaunched(activity, temperature);
            mList.get(i).onActivityLaunched(id, name, temperature);
        }
    }

    private void handleOnActivityLaunchCancelled(
            @ActivityRecordProto byte[] activity) {
    private void handleOnActivityLaunchCancelled(long id) {
        // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
        for (int i = 0; i < mList.size(); i++) {
             ActivityMetricsLaunchObserver o = mList.get(i);
             o.onActivityLaunchCancelled(activity);
            mList.get(i).onActivityLaunchCancelled(id);
        }
    }

    private void handleOnActivityLaunchFinished(
            @ActivityRecordProto byte[] activity, long timestampNs) {
    private void handleOnActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
        // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
        for (int i = 0; i < mList.size(); i++) {
            ActivityMetricsLaunchObserver o = mList.get(i);
            o.onActivityLaunchFinished(activity, timestampNs);
            mList.get(i).onActivityLaunchFinished(id, name, timestampNs);
        }
    }

    private void handleOnReportFullyDrawn(
            @ActivityRecordProto byte[] activity, long timestampNs) {
    private void handleOnReportFullyDrawn(long id, long timestampNs) {
        // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
        for (int i = 0; i < mList.size(); i++) {
            ActivityMetricsLaunchObserver o = mList.get(i);
            o.onReportFullyDrawn(activity, timestampNs);
            mList.get(i).onReportFullyDrawn(id, timestampNs);
        }
    }
}
+1 −26
Original line number Diff line number Diff line
@@ -274,36 +274,11 @@ public final class ProfcollectForwardingService extends SystemService {
        }
    }

    private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
    private class AppLaunchObserver extends ActivityMetricsLaunchObserver {
        @Override
        public void onIntentStarted(Intent intent, long timestampNanos) {
            traceOnAppStart(intent.getPackage());
        }

        @Override
        public void onIntentFailed() {
            // Ignored
        }

        @Override
        public void onActivityLaunched(byte[] activity, int temperature) {
            // Ignored
        }

        @Override
        public void onActivityLaunchCancelled(byte[] abortingActivity) {
            // Ignored
        }

        @Override
        public void onActivityLaunchFinished(byte[] finalActivity, long timestampNanos) {
            // Ignored
        }

        @Override
        public void onReportFullyDrawn(byte[] activity, long timestampNanos) {
            // Ignored
        }
    }

    private void registerOTAObserver() {
Loading