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

Commit a1c29b99 authored by Yu-Ting Tseng's avatar Yu-Ting Tseng Committed by Automerger Merge Worker
Browse files

Merge "Revert^2 "Address frozen notification API feedback"" into main am: 1c68f8cc am: 8b7a8875

parents b2a487a6 8b7a8875
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -33809,7 +33809,7 @@ package android.os {
  }
  public interface IBinder {
    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
    method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
    method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
    method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
@@ -34440,6 +34440,7 @@ package android.os {
    method public void finishBroadcast();
    method public Object getBroadcastCookie(int);
    method public E getBroadcastItem(int);
    method @FlaggedApi("android.os.binder_frozen_state_change_callback") @Nullable public java.util.concurrent.Executor getExecutor();
    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getFrozenCalleePolicy();
    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getMaxQueueSize();
    method public Object getRegisteredCallbackCookie(int);
@@ -34460,6 +34461,7 @@ package android.os {
  @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final class RemoteCallbackList.Builder<E extends android.os.IInterface> {
    ctor public RemoteCallbackList.Builder(int);
    method @NonNull public android.os.RemoteCallbackList<E> build();
    method @NonNull public android.os.RemoteCallbackList.Builder setExecutor(@NonNull java.util.concurrent.Executor);
    method @NonNull public android.os.RemoteCallbackList.Builder setInterfaceDiedCallback(@NonNull android.os.RemoteCallbackList.Builder.InterfaceDiedCallback<E>);
    method @NonNull public android.os.RemoteCallbackList.Builder setMaxQueueSize(int);
  }
+23 −11
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@@ -651,28 +652,39 @@ public final class BinderProxy implements IBinder {
    private native boolean unlinkToDeathNative(DeathRecipient recipient, int flags);

    /**
     * This list is to hold strong reference to the frozen state callbacks. The callbacks are only
     * weakly referenced by JNI so the strong references here are needed to keep the callbacks
     * around until the proxy is GC'ed.
     * This map is to hold strong reference to the frozen state callbacks.
     *
     * The callbacks are only weakly referenced by JNI so the strong references here are needed to
     * keep the callbacks around until the proxy is GC'ed.
     *
     * The key is the original callback passed into {@link #addFrozenStateChangeCallback}. The value
     * is the wrapped callback created in {@link #addFrozenStateChangeCallback} to dispatch the
     * calls on the desired executor.
     */
    private List<FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
            Collections.synchronizedList(new ArrayList<>());
    private Map<FrozenStateChangeCallback, FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
            Collections.synchronizedMap(new HashMap<>());

    /**
     * See {@link IBinder#addFrozenStateChangeCallback(FrozenStateChangeCallback)}
     */
    public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
    public void addFrozenStateChangeCallback(Executor executor, FrozenStateChangeCallback callback)
            throws RemoteException {
        addFrozenStateChangeCallbackNative(callback);
        mFrozenStateChangeCallbacks.add(callback);
        FrozenStateChangeCallback wrappedCallback = (who, state) ->
                executor.execute(() -> callback.onFrozenStateChanged(who, state));
        addFrozenStateChangeCallbackNative(wrappedCallback);
        mFrozenStateChangeCallbacks.put(callback, wrappedCallback);
    }

    /**
     * See {@link IBinder#removeFrozenStateChangeCallback}
     */
    public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
        mFrozenStateChangeCallbacks.remove(callback);
        return removeFrozenStateChangeCallbackNative(callback);
    public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback)
            throws IllegalArgumentException {
        FrozenStateChangeCallback wrappedCallback = mFrozenStateChangeCallbacks.remove(callback);
        if (wrappedCallback == null) {
            throw new IllegalArgumentException("callback not found");
        }
        return removeFrozenStateChangeCallbackNative(wrappedCallback);
    }

    private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback)
+38 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.os;

import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -25,6 +26,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;

/**
 * Base interface for a remotable object, the core part of a lightweight
@@ -397,12 +399,31 @@ public interface IBinder {
        @interface State {
        }

        /**
         * Represents the frozen state of the remote process.
         *
         * While in this state, the remote process won't be able to receive and handle a
         * transaction. Therefore, any asynchronous transactions will be buffered and delivered when
         * the process is unfrozen, and any synchronous transactions will result in an error.
         *
         * Buffered transactions may be stale by the time that the process is unfrozen and handles
         * them. To avoid overwhelming the remote process with stale events or overflowing their
         * buffers, it's best to avoid sending binder transactions to a frozen process.
         */
        int STATE_FROZEN = 0;

        /**
         * Represents the unfrozen state of the remote process.
         *
         * In this state, the process hosting the object can execute and is not restricted
         * by the freezer from using the CPU or responding to binder transactions.
         */
        int STATE_UNFROZEN = 1;

        /**
         * Interface for receiving a callback when the process hosting an IBinder
         * has changed its frozen state.
         *
         * @param who The IBinder whose hosting process has changed state.
         * @param state The latest state.
         */
@@ -427,15 +448,31 @@ public interface IBinder {
     * <p>You will only receive state change notifications for remote binders, as local binders by
     * definition can't be frozen without you being frozen too.</p>
     *
     * @param executor The executor on which to run the callback.
     * @param callback The callback used to deliver state change notifications.
     *
     * <p>@throws {@link UnsupportedOperationException} if the kernel binder driver does not support
     * this feature.
     */
    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
    default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
    default void addFrozenStateChangeCallback(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull FrozenStateChangeCallback callback)
            throws RemoteException {
        throw new UnsupportedOperationException();
    }

    /**
     * Same as {@link #addFrozenStateChangeCallback(Executor, FrozenStateChangeCallback)} except
     * that callbacks are invoked on a binder thread.
     *
     * @hide
     */
    default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
            throws RemoteException {
        addFrozenStateChangeCallback(Runnable::run, callback);
    }

    /**
     * Unregister a {@link FrozenStateChangeCallback}. The callback will no longer be invoked when
     * the hosting process changes its frozen state.
+41 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.os;

import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -29,6 +30,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

@@ -134,6 +136,7 @@ public class RemoteCallbackList<E extends IInterface> {

    private final @FrozenCalleePolicy int mFrozenCalleePolicy;
    private final int mMaxQueueSize;
    private final Executor mExecutor;

    private final class Interface implements IBinder.DeathRecipient,
            IBinder.FrozenStateChangeCallback {
@@ -197,7 +200,7 @@ public class RemoteCallbackList<E extends IInterface> {
        void maybeSubscribeToFrozenCallback() throws RemoteException {
            if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
                try {
                    mBinder.addFrozenStateChangeCallback(this);
                    mBinder.addFrozenStateChangeCallback(mExecutor, this);
                } catch (UnsupportedOperationException e) {
                    // The kernel does not support frozen notifications. In this case we want to
                    // silently fall back to FROZEN_CALLEE_POLICY_UNSET. This is done by simply
@@ -237,6 +240,7 @@ public class RemoteCallbackList<E extends IInterface> {
        private @FrozenCalleePolicy int mFrozenCalleePolicy;
        private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
        private InterfaceDiedCallback mInterfaceDiedCallback;
        private Executor mExecutor;

        /**
         * Creates a Builder for {@link RemoteCallbackList}.
@@ -284,6 +288,18 @@ public class RemoteCallbackList<E extends IInterface> {
            return this;
        }

        /**
         * Sets the executor to be used when invoking callbacks asynchronously.
         *
         * This is only used when callbacks need to be invoked asynchronously, e.g. when the process
         * hosting a callback becomes unfrozen. Callbacks that can be invoked immediately run on the
         * same thread that calls {@link #broadcast} synchronously.
         */
        public @NonNull Builder setExecutor(@NonNull @CallbackExecutor Executor executor) {
            mExecutor = executor;
            return this;
        }

        /**
         * For notifying when the process hosting a callback interface has died.
         *
@@ -308,15 +324,21 @@ public class RemoteCallbackList<E extends IInterface> {
         * @return The built {@link RemoteCallbackList} object.
         */
        public @NonNull RemoteCallbackList<E> build() {
            Executor executor = mExecutor;
            if (executor == null && mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
                // TODO Throw an exception here once the existing API caller is updated to provide
                // an executor.
                executor = new HandlerExecutor(Handler.getMain());
            }
            if (mInterfaceDiedCallback != null) {
                return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize) {
                return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor) {
                    @Override
                    public void onCallbackDied(E deadInterface, Object cookie) {
                        mInterfaceDiedCallback.onInterfaceDied(this, deadInterface, cookie);
                    }
                };
            }
            return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize);
            return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor);
        }
    }

@@ -340,6 +362,16 @@ public class RemoteCallbackList<E extends IInterface> {
        return mMaxQueueSize;
    }

    /**
     * Returns the executor used when invoking callbacks asynchronously.
     *
     * @return The executor.
     */
    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
    public @Nullable Executor getExecutor() {
        return mExecutor;
    }

    /**
     * Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to
     * <pre>
@@ -347,7 +379,7 @@ public class RemoteCallbackList<E extends IInterface> {
     * </pre>
     */
    public RemoteCallbackList() {
        this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE);
        this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE, null);
    }

    /**
@@ -362,10 +394,14 @@ public class RemoteCallbackList<E extends IInterface> {
     * recipient's process is frozen. Once the limit is reached, the oldest callbacks would be
     * dropped to keep the size under limit. Ignored except for
     * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
     *
     * @param executor The executor used when invoking callbacks asynchronously.
     */
    private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize) {
    private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize,
            @CallbackExecutor Executor executor) {
        mFrozenCalleePolicy = frozenCalleePolicy;
        mMaxQueueSize = maxQueueSize;
        mExecutor = executor;
    }

    /**
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.frameworks.coretests.bfscctestapp;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.RemoteException;

@@ -36,6 +38,7 @@ public class BfsccTestAppCmdService extends Service {
        @Override
        public void listenTo(IBinder binder) throws RemoteException {
            binder.addFrozenStateChangeCallback(
                    new HandlerExecutor(Handler.getMain()),
                    (IBinder who, int state) -> mNotifications.offer(state));
        }

Loading