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

Commit 7762547c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "wm: Add ActivityMetricsLaunchObserverRegistry"

parents cce6c22e c0b47e4e
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ import java.lang.annotation.RetentionPolicy;
 * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled}
 * or into {@code FINISHED} with {@link #onActivityLaunchFinished}. These are terminal states.
 *
 * Note that the {@link ActivityRecord} provided as a parameter to some state transitions isn't
 * Note that the {@code ActivityRecordProto} 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.
@@ -93,6 +93,14 @@ 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.
     *
@@ -135,7 +143,7 @@ public interface ActivityMetricsLaunchObserver {
     * Multiple calls to this method cannot occur without first terminating the current
     * launch sequence.
     */
    public void onActivityLaunched(@NonNull ActivityRecord activity,
    public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
                                   @Temperature int temperature);

    /**
@@ -157,7 +165,7 @@ public interface ActivityMetricsLaunchObserver {
     *          in the case of a trampoline, multiple activities could've been started
     *          and only the latest activity is reported here.
     */
    public void onActivityLaunchCancelled(@Nullable ActivityRecord abortingActivity);
    public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] abortingActivity);

    /**
     * Notifies the observer that the current launch sequence has been successfully finished.
@@ -178,5 +186,5 @@ public interface ActivityMetricsLaunchObserver {
     *          and only the latest activity that was top-most during first-frame drawn
     *          is reported here.
     */
    public void onActivityLaunchFinished(@NonNull ActivityRecord finalActivity);
    public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity);
}
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

package com.android.server.wm;

import android.annotation.NonNull;

/**
 * Multi-cast delegate implementation for {@link ActivityMetricsLaunchObserver}.
 *
 * <br/><br/>
 * This enables multiple launch observers to subscribe to {@link ActivityMetricsLogger}
 * independently of each other.
 *
 * <br/><br/>
 * Some callbacks in {@link ActivityMetricsLaunchObserver} have a {@code byte[]}
 * parameter; this array is reused by all the registered observers, so it must not be written to
 * (i.e. all observers must treat any array parameters as immutable).
 *
 * <br /><br />
 * Multi-cast invocations occurs sequentially in-order of registered observers.
 */
public interface ActivityMetricsLaunchObserverRegistry {
    /**
     * Register an extra launch observer to receive the multi-cast.
     *
     * <br /><br />
     * Multi-cast invocation happens in the same order the observers were registered. For example,
     * <pre>
     *     registerLaunchObserver(A)
     *     registerLaunchObserver(B)
     *
     *     obs.onIntentFailed() ->
     *       A.onIntentFailed()
     *       B.onIntentFailed()
     * </pre>
     */
    void registerLaunchObserver(@NonNull ActivityMetricsLaunchObserver launchObserver);

    /**
     * Unregister an existing launch observer. It will not receive the multi-cast in the future.
     *
     * <br /><br />
     * This does nothing if this observer was not already registered.
     */
    void unregisterLaunchObserver(@NonNull ActivityMetricsLaunchObserver launchObserver);
}
+65 −21
Original line number Diff line number Diff line
@@ -99,10 +99,12 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;

/**
@@ -168,7 +170,8 @@ class ActivityMetricsLogger {
     * Due to the global single concurrent launch sequence, all calls to this observer must be made
     * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
     */
    private final ActivityMetricsLaunchObserver mLaunchObserver = null;
    private final LaunchObserverRegistryImpl mLaunchObserver;
    @VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;

    private final class H extends Handler {

@@ -263,6 +266,7 @@ class ActivityMetricsLogger {
        mSupervisor = supervisor;
        mContext = context;
        mHandler = new H(looper);
        mLaunchObserver = new LaunchObserverRegistryImpl(looper);
    }

    void logWindowState() {
@@ -1000,12 +1004,19 @@ class ActivityMetricsLogger {
        }
    }

    public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() {
        return mLaunchObserver;
    }

    /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */
    private void launchObserverNotifyIntentStarted(Intent intent) {
        if (mLaunchObserver != null) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyIntentStarted");

        // Beginning a launch is timing sensitive and so should be observed as soon as possible.
        mLaunchObserver.onIntentStarted(intent);
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

    /**
@@ -1014,9 +1025,12 @@ class ActivityMetricsLogger {
     * intent being delivered to the top running activity.
     */
    private void launchObserverNotifyIntentFailed() {
        if (mLaunchObserver != null) {
       Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyIntentFailed");

        mLaunchObserver.onIntentFailed();
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

    /**
@@ -1024,14 +1038,17 @@ class ActivityMetricsLogger {
     * has started.
     */
    private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyActivityLaunched");

        @ActivityMetricsLaunchObserver.Temperature int temperature =
                convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info));

        if (mLaunchObserver != null) {
        // Beginning a launch is timing sensitive and so should be observed as soon as possible.
            mLaunchObserver.onActivityLaunched(info.launchedActivity,
        mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.launchedActivity),
                                           temperature);
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

    /**
@@ -1039,11 +1056,15 @@ class ActivityMetricsLogger {
     * cancelled.
     */
    private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) {
        final ActivityRecord launchedActivity = info != null ? info.launchedActivity : null;
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyActivityLaunchCancelled");

        if (mLaunchObserver != null) {
            mLaunchObserver.onActivityLaunchCancelled(launchedActivity);
        }
        final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
                info != null ? convertActivityRecordToProto(info.launchedActivity) : null;

        mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }

    /**
@@ -1051,11 +1072,34 @@ class ActivityMetricsLogger {
     * has fully finished (successfully).
     */
    private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info) {
        final ActivityRecord launchedActivity = info.launchedActivity;
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                "MetricsLogger:launchObserverNotifyActivityLaunchFinished");

        mLaunchObserver.onActivityLaunchFinished(
                convertActivityRecordToProto(info.launchedActivity));

        if (mLaunchObserver != null) {
            mLaunchObserver.onActivityLaunchFinished(launchedActivity);
        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.writeToProto(protoOutputStream);
        final byte[] bytes = protoOutputStream.getBytes();

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        return bytes;
    }

    private static @ActivityMetricsLaunchObserver.Temperature int
+10 −2
Original line number Diff line number Diff line
@@ -3215,8 +3215,11 @@ final class ActivityRecord extends ConfigurationContainer {
        proto.end(token);
    }

    public void writeToProto(ProtoOutputStream proto, long fieldId) {
        final long token = proto.start(fieldId);
    /**
     * Write all fields to an {@code ActivityRecordProto}. This assumes the
     * {@code ActivityRecordProto} is the outer-most proto data.
     */
    void writeToProto(ProtoOutputStream proto) {
        super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
        writeIdentifierToProto(proto, IDENTIFIER);
        proto.write(STATE, mState.toString());
@@ -3226,6 +3229,11 @@ final class ActivityRecord extends ConfigurationContainer {
            proto.write(PROC_ID, app.getPid());
        }
        proto.write(TRANSLUCENT, !fullscreen);
    }

    public void writeToProto(ProtoOutputStream proto, long fieldId) {
        final long token = proto.start(fieldId);
        writeToProto(proto);
        proto.end(token);
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -434,7 +434,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {

        mInitialized = true;
        mRunningTasks = createRunningTasks();
        mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext, mHandler.getLooper());

        mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext,
                mHandler.getLooper());
        mKeyguardController = new KeyguardController(mService, this);

        mPersisterQueue = new PersisterQueue();
Loading