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

Commit d7864133 authored by Yisroel Forta's avatar Yisroel Forta
Browse files

AppStartInfo API Updates

Allow apps to set more than 1 onComplete listener.

Improve javadoc

Test: register multiple listeners, remove some, ensure correct ones are called.

Bug: 293139587
Change-Id: Ia33fde679f0b7c9bd9668054448616fa7160f8c5
parent 250a46c7
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -4621,9 +4621,9 @@ package android.app {
  public class ActivityManager {
    method public int addAppTask(@NonNull android.app.Activity, @NonNull android.content.Intent, @Nullable android.app.ActivityManager.TaskDescription, @NonNull android.graphics.Bitmap);
    method @FlaggedApi("android.app.app_start_info") public void addApplicationStartInfoCompletionListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.ApplicationStartInfo>);
    method @FlaggedApi("android.app.app_start_info") public void addStartInfoTimestamp(@IntRange(from=android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START, to=android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER) int, long);
    method public void appNotResponding(@NonNull String);
    method @FlaggedApi("android.app.app_start_info") public void clearApplicationStartInfoCompletionListener();
    method public boolean clearApplicationUserData();
    method public void clearWatchHeapLimit();
    method @RequiresPermission(android.Manifest.permission.DUMP) public void dumpPackageState(java.io.FileDescriptor, String);
@@ -4657,8 +4657,8 @@ package android.app {
    method @RequiresPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES) public void killBackgroundProcesses(String);
    method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int);
    method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int, android.os.Bundle);
    method @FlaggedApi("android.app.app_start_info") public void removeApplicationStartInfoCompletionListener(@NonNull java.util.function.Consumer<android.app.ApplicationStartInfo>);
    method @Deprecated public void restartPackage(String);
    method @FlaggedApi("android.app.app_start_info") public void setApplicationStartInfoCompletionListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.ApplicationStartInfo>);
    method public void setProcessStateSummary(@Nullable byte[]);
    method public static void setVrThread(int);
    method public void setWatchHeapLimit(long);
+80 −18
Original line number Diff line number Diff line
@@ -4052,10 +4052,28 @@ public class ActivityManager {
        }
    }

    private final ArrayList<AppStartInfoCallbackWrapper> mAppStartInfoCallbacks =
            new ArrayList<>();
    @Nullable
    private IApplicationStartInfoCompleteListener mAppStartInfoCompleteListener = null;

    private static final class AppStartInfoCallbackWrapper {
        @NonNull final Executor mExecutor;
        @NonNull final Consumer<ApplicationStartInfo> mListener;

        AppStartInfoCallbackWrapper(@NonNull final Executor executor,
                @NonNull final Consumer<ApplicationStartInfo> listener) {
            mExecutor = executor;
            mListener = listener;
        }
    }

    /**
     * Sets a callback to be notified when the {@link ApplicationStartInfo} records of this startup
     * Adds a callback to be notified when the {@link ApplicationStartInfo} records of this startup
     * are complete.
     *
     * <p class="note"> Note: callback will be removed automatically after being triggered.</p>
     *
     * <p class="note"> Note: callback will not wait for {@link Activity#reportFullyDrawn} to occur.
     * Timestamp for fully drawn may be added after callback occurs. Set callback after invoking
     * {@link Activity#reportFullyDrawn} if timestamp for fully drawn is required.</p>
@@ -4073,34 +4091,78 @@ public class ActivityManager {
     * @throws IllegalArgumentException if executor or listener are null.
     */
    @FlaggedApi(Flags.FLAG_APP_START_INFO)
    public void setApplicationStartInfoCompletionListener(@NonNull final Executor executor,
    public void addApplicationStartInfoCompletionListener(@NonNull final Executor executor,
            @NonNull final Consumer<ApplicationStartInfo> listener) {
        Preconditions.checkNotNull(executor, "executor cannot be null");
        Preconditions.checkNotNull(listener, "listener cannot be null");
        IApplicationStartInfoCompleteListener callback =
                new IApplicationStartInfoCompleteListener.Stub() {
        synchronized (mAppStartInfoCallbacks) {
            for (int i = 0; i < mAppStartInfoCallbacks.size(); i++) {
                if (listener.equals(mAppStartInfoCallbacks.get(i).mListener)) {
                    return;
                }
            }
            if (mAppStartInfoCompleteListener == null) {
                mAppStartInfoCompleteListener = new IApplicationStartInfoCompleteListener.Stub() {
                    @Override
            public void onApplicationStartInfoComplete(ApplicationStartInfo applicationStartInfo) {
                executor.execute(() -> listener.accept(applicationStartInfo));
                    public void onApplicationStartInfoComplete(
                            ApplicationStartInfo applicationStartInfo) {
                        synchronized (mAppStartInfoCallbacks) {
                            for (int i = 0; i < mAppStartInfoCallbacks.size(); i++) {
                                final AppStartInfoCallbackWrapper callback =
                                        mAppStartInfoCallbacks.get(i);
                                callback.mExecutor.execute(() -> callback.mListener.accept(
                                        applicationStartInfo));
                            }
                            mAppStartInfoCallbacks.clear();
                            mAppStartInfoCompleteListener = null;
                        }
                    }
                };
                boolean succeeded = false;
                try {
            getService().setApplicationStartInfoCompleteListener(callback, mContext.getUserId());
                    getService().addApplicationStartInfoCompleteListener(
                            mAppStartInfoCompleteListener, mContext.getUserId());
                    succeeded = true;
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                if (succeeded) {
                    mAppStartInfoCallbacks.add(new AppStartInfoCallbackWrapper(executor, listener));
                } else {
                    mAppStartInfoCompleteListener = null;
                    mAppStartInfoCallbacks.clear();
                }
            } else {
                mAppStartInfoCallbacks.add(new AppStartInfoCallbackWrapper(executor, listener));
            }
        }
    }

    /**
     * Removes the callback set by {@link #setApplicationStartInfoCompletionListener} if there is one.
     * Removes the provided callback set by {@link #addApplicationStartInfoCompletionListener}.
     */
    @FlaggedApi(Flags.FLAG_APP_START_INFO)
    public void clearApplicationStartInfoCompletionListener() {
    public void removeApplicationStartInfoCompletionListener(
            @NonNull final Consumer<ApplicationStartInfo> listener) {
        Preconditions.checkNotNull(listener, "listener cannot be null");
        synchronized (mAppStartInfoCallbacks) {
            for (int i = 0; i < mAppStartInfoCallbacks.size(); i++) {
                final AppStartInfoCallbackWrapper callback = mAppStartInfoCallbacks.get(i);
                if (listener.equals(callback.mListener)) {
                    mAppStartInfoCallbacks.remove(i);
                    break;
                }
            }
            if (mAppStartInfoCompleteListener != null && mAppStartInfoCallbacks.isEmpty()) {
                try {
            getService().clearApplicationStartInfoCompleteListener(mContext.getUserId());
                    getService().removeApplicationStartInfoCompleteListener(
                            mAppStartInfoCompleteListener, mContext.getUserId());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                mAppStartInfoCompleteListener = null;
            }
        }
    }

    /**
+18 −16
Original line number Diff line number Diff line
@@ -39,12 +39,17 @@ import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Provide information related to a processes startup.
 * Describes information related to an application process's startup.
 *
 * <p>
 * Many aspects concerning why and how an applications process was started are valuable for apps
 * both for logging and for potential behavior changes. Reason for process start, start type,
 * start times, throttling, and other useful diagnostic data can be obtained from
 * {@link ApplicationStartInfo} records.
 * </p>
 */
@FlaggedApi(Flags.FLAG_APP_START_INFO)
public final class ApplicationStartInfo implements Parcelable {
@@ -552,13 +557,12 @@ public final class ApplicationStartInfo implements Parcelable {
        dest.writeInt(mDefiningUid);
        dest.writeString(mProcessName);
        dest.writeInt(mReason);
        dest.writeInt(mStartupTimestampsNs.size());
        Set<Map.Entry<Integer, Long>> timestampEntrySet = mStartupTimestampsNs.entrySet();
        Iterator<Map.Entry<Integer, Long>> iter = timestampEntrySet.iterator();
        while (iter.hasNext()) {
            Map.Entry<Integer, Long> entry = iter.next();
            dest.writeInt(entry.getKey());
            dest.writeLong(entry.getValue());
        dest.writeInt(mStartupTimestampsNs == null ? 0 : mStartupTimestampsNs.size());
        if (mStartupTimestampsNs != null) {
            for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
                dest.writeInt(mStartupTimestampsNs.keyAt(i));
                dest.writeLong(mStartupTimestampsNs.valueAt(i));
            }
        }
        dest.writeInt(mStartType);
        dest.writeParcelable(mStartIntent, flags);
@@ -740,13 +744,11 @@ public final class ApplicationStartInfo implements Parcelable {
            sb.append(" intent=").append(mStartIntent.toString())
                .append('\n');
        }
        if (mStartupTimestampsNs.size() > 0) {
        if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
            sb.append(" timestamps: ");
            Set<Map.Entry<Integer, Long>> timestampEntrySet = mStartupTimestampsNs.entrySet();
            Iterator<Map.Entry<Integer, Long>> iter = timestampEntrySet.iterator();
            while (iter.hasNext()) {
                Map.Entry<Integer, Long> entry = iter.next();
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append(" ");
            for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
                sb.append(mStartupTimestampsNs.keyAt(i)).append("=").append(mStartupTimestampsNs
                        .valueAt(i)).append(" ");
            }
            sb.append('\n');
        }
+3 −2
Original line number Diff line number Diff line
@@ -715,7 +715,7 @@ interface IActivityManager {
     * @param listener    A listener to for the callback upon completion of startup data collection.
     * @param userId      The userId in the multi-user environment.
     */
    void setApplicationStartInfoCompleteListener(IApplicationStartInfoCompleteListener listener,
    void addApplicationStartInfoCompleteListener(IApplicationStartInfoCompleteListener listener,
            int userId);


@@ -724,7 +724,8 @@ interface IActivityManager {
     *
     * @param userId      The userId in the multi-user environment.
     */
    void clearApplicationStartInfoCompleteListener(int userId);
    void removeApplicationStartInfoCompleteListener(IApplicationStartInfoCompleteListener listener,
            int userId);


    /**
+5 −3
Original line number Diff line number Diff line
@@ -9857,7 +9857,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    @Override
    public void setApplicationStartInfoCompleteListener(
    public void addApplicationStartInfoCompleteListener(
            IApplicationStartInfoCompleteListener listener, int userId) {
        enforceNotIsolatedCaller("setApplicationStartInfoCompleteListener");
@@ -9872,7 +9872,8 @@ public class ActivityManagerService extends IActivityManager.Stub
    @Override
    public void clearApplicationStartInfoCompleteListener(int userId) {
    public void removeApplicationStartInfoCompleteListener(
            IApplicationStartInfoCompleteListener listener, int userId) {
        enforceNotIsolatedCaller("clearApplicationStartInfoCompleteListener");
        // For the simplification, we don't support USER_ALL nor USER_CURRENT here.
@@ -9881,7 +9882,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        final int callingUid = Binder.getCallingUid();
        mProcessList.getAppStartInfoTracker().clearStartInfoCompleteListener(callingUid, true);
        mProcessList.getAppStartInfoTracker().removeStartInfoCompleteListener(listener, callingUid,
                true);
    }
    @Override
Loading