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

Commit e0d21194 authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

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

parents 1b819932 4a263005
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