Merge "Remove hidden VcnTransportInfo methods from VpnTest" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index d2e89b4..6869d93 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -33882,9 +33882,12 @@
public class RemoteCallbackList<E extends android.os.IInterface> {
ctor public RemoteCallbackList();
method public int beginBroadcast();
+ method @FlaggedApi("android.os.binder_frozen_state_change_callback") public void broadcast(@NonNull java.util.function.Consumer<E>);
method public void finishBroadcast();
method public Object getBroadcastCookie(int);
method public E getBroadcastItem(int);
+ 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);
method public int getRegisteredCallbackCount();
method public E getRegisteredCallbackItem(int);
@@ -33894,6 +33897,21 @@
method public boolean register(E);
method public boolean register(E, Object);
method public boolean unregister(E);
+ field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_DROP = 3; // 0x3
+ field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_ENQUEUE_ALL = 1; // 0x1
+ field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT = 2; // 0x2
+ field @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final int FROZEN_CALLEE_POLICY_UNSET = 0; // 0x0
+ }
+
+ @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 setInterfaceDiedCallback(@NonNull android.os.RemoteCallbackList.Builder.InterfaceDiedCallback<E>);
+ method @NonNull public android.os.RemoteCallbackList.Builder setMaxQueueSize(int);
+ }
+
+ @FlaggedApi("android.os.binder_frozen_state_change_callback") public static interface RemoteCallbackList.Builder.InterfaceDiedCallback<E extends android.os.IInterface> {
+ method public void onInterfaceDied(@NonNull android.os.RemoteCallbackList<E>, E, @Nullable Object);
}
public class RemoteException extends android.util.AndroidException {
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index e6a7ca5..a8e5e20 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -383,6 +383,10 @@
Method javax.microedition.khronos.egl.EGL10.eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match
+ExecutorRegistration: android.os.IBinder#addFrozenStateChangeCallback(android.os.IBinder.FrozenStateChangeCallback):
+ Registration methods should have overload that accepts delivery Executor: `addFrozenStateChangeCallback`
+
+
InvalidNullabilityOverride: android.app.Notification.TvExtender#extend(android.app.Notification.Builder) parameter #0:
Invalid nullability on parameter `builder` in method `extend`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: android.media.midi.MidiUmpDeviceService#onBind(android.content.Intent) parameter #0:
@@ -395,6 +399,10 @@
Method can be invoked with an indexing operator from Kotlin: `set` (this is usually desirable; just make sure it makes sense for this type of object)
+MissingGetterMatchingBuilder: android.os.RemoteCallbackList.Builder#setInterfaceDiedCallback(android.os.RemoteCallbackList.Builder.InterfaceDiedCallback<E>):
+ android.os.RemoteCallbackList does not declare a `getInterfaceDiedCallback()` method matching method android.os.RemoteCallbackList.Builder.setInterfaceDiedCallback(android.os.RemoteCallbackList.Builder.InterfaceDiedCallback<E>)
+
+
RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler):
Method 'getAccountsByTypeAndFeatures' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
@@ -1445,7 +1453,6 @@
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getItalicOverride(int)
UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
-
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_CAR:
New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_CAR
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_COMPUTER:
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8de86d5..2df187b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -292,6 +292,10 @@
* <p>
* The value of a property will only have a single type, as defined by
* the property itself.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * In android version {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and earlier,
+ * the {@code equals} and {@code hashCode} methods for this class may not function as expected.
*/
public static final class Property implements Parcelable {
private static final int TYPE_BOOLEAN = 1;
@@ -523,6 +527,40 @@
return new Property[size];
}
};
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Property)) {
+ return false;
+ }
+ final Property property = (Property) obj;
+ return mType == property.mType &&
+ Objects.equals(mName, property.mName) &&
+ Objects.equals(mClassName, property.mClassName) &&
+ Objects.equals(mPackageName, property.mPackageName) &&
+ (mType == TYPE_BOOLEAN ? mBooleanValue == property.mBooleanValue :
+ mType == TYPE_FLOAT ? Float.compare(mFloatValue, property.mFloatValue) == 0 :
+ mType == TYPE_INTEGER ? mIntegerValue == property.mIntegerValue :
+ mType == TYPE_RESOURCE ? mIntegerValue == property.mIntegerValue :
+ mStringValue.equals(property.mStringValue));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mName, mType, mClassName, mPackageName);
+ if (mType == TYPE_BOOLEAN) {
+ result = 31 * result + (mBooleanValue ? 1 : 0);
+ } else if (mType == TYPE_FLOAT) {
+ result = 31 * result + Float.floatToIntBits(mFloatValue);
+ } else if (mType == TYPE_INTEGER) {
+ result = 31 * result + mIntegerValue;
+ } else if (mType == TYPE_RESOURCE) {
+ result = 31 * result + mIntegerValue;
+ } else if (mType == TYPE_STRING) {
+ result = 31 * result + mStringValue.hashCode();
+ }
+ return result;
+ }
}
/**
diff --git a/core/java/android/hardware/contexthub/OWNERS b/core/java/android/hardware/contexthub/OWNERS
new file mode 100644
index 0000000..a65a2bf
--- /dev/null
+++ b/core/java/android/hardware/contexthub/OWNERS
@@ -0,0 +1,2 @@
+# ContextHub team
+file:platform/system/chre:/OWNERS
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 590ddb4..24e1d66 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -78,6 +78,9 @@
# PermissionEnforcer
per-file PermissionEnforcer.java = tweek@google.com, brufino@google.com
+# RemoteCallbackList
+per-file RemoteCallbackList.java = shayba@google.com
+
# ART
per-file ArtModuleServiceManager.java = file:platform/art:/OWNERS
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 2cb86f7..91c482fa 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,11 +16,19 @@
package android.os;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Slog;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -30,7 +38,7 @@
* {@link android.app.Service} to its clients. In particular, this:
*
* <ul>
- * <li> Keeps track of a set of registered {@link IInterface} callbacks,
+ * <li> Keeps track of a set of registered {@link IInterface} objects,
* taking care to identify them through their underlying unique {@link IBinder}
* (by calling {@link IInterface#asBinder IInterface.asBinder()}.
* <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to
@@ -47,7 +55,7 @@
* the registered clients, use {@link #beginBroadcast},
* {@link #getBroadcastItem}, and {@link #finishBroadcast}.
*
- * <p>If a registered callback's process goes away, this class will take
+ * <p>If a registered interface's process goes away, this class will take
* care of automatically removing it from the list. If you want to do
* additional work in this situation, you can create a subclass that
* implements the {@link #onCallbackDied} method.
@@ -56,78 +64,358 @@
public class RemoteCallbackList<E extends IInterface> {
private static final String TAG = "RemoteCallbackList";
+ private static final int DEFAULT_MAX_QUEUE_SIZE = 1000;
+
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"FROZEN_CALLEE_POLICY_"}, value = {
+ FROZEN_CALLEE_POLICY_UNSET,
+ FROZEN_CALLEE_POLICY_ENQUEUE_ALL,
+ FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT,
+ FROZEN_CALLEE_POLICY_DROP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface FrozenCalleePolicy {
+ }
+
+ /**
+ * Callbacks are invoked immediately regardless of the frozen state of the target process.
+ *
+ * Not recommended. Only exists for backward-compatibility. This represents the behavior up to
+ * SDK 35. Starting with SDK 36, clients should set a policy to govern callback invocations when
+ * recipients are frozen.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public static final int FROZEN_CALLEE_POLICY_UNSET = 0;
+
+ /**
+ * When the callback recipient's process is frozen, callbacks are enqueued so they're invoked
+ * after the recipient is unfrozen.
+ *
+ * This is commonly used when the recipient wants to receive all callbacks without losing any
+ * history, e.g. the recipient maintains a running count of events that occurred.
+ *
+ * Queued callbacks are invoked in the order they were originally broadcasted.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public static final int FROZEN_CALLEE_POLICY_ENQUEUE_ALL = 1;
+
+ /**
+ * When the callback recipient's process is frozen, only the most recent callback is enqueued,
+ * which is later invoked after the recipient is unfrozen.
+ *
+ * This can be used when only the most recent state matters, for instance when clients are
+ * listening to screen brightness changes.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public static final int FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT = 2;
+
+ /**
+ * When the callback recipient's process is frozen, callbacks are suppressed as if they never
+ * happened.
+ *
+ * This could be useful in the case where the recipient wishes to react to callbacks only when
+ * they occur while the recipient is not frozen. For example, certain network events are only
+ * worth responding to if the response can be immediate. Another example is recipients having
+ * another way of getting the latest state once it's unfrozen. Therefore there is no need to
+ * save callbacks that happened while the recipient was frozen.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public static final int FROZEN_CALLEE_POLICY_DROP = 3;
+
@UnsupportedAppUsage
- /*package*/ ArrayMap<IBinder, Callback> mCallbacks
- = new ArrayMap<IBinder, Callback>();
+ /*package*/ ArrayMap<IBinder, Interface> mInterfaces = new ArrayMap<IBinder, Interface>();
private Object[] mActiveBroadcast;
private int mBroadcastCount = -1;
private boolean mKilled = false;
private StringBuilder mRecentCallers;
- private final class Callback implements IBinder.DeathRecipient {
- final E mCallback;
- final Object mCookie;
+ private final @FrozenCalleePolicy int mFrozenCalleePolicy;
+ private final int mMaxQueueSize;
- Callback(E callback, Object cookie) {
- mCallback = callback;
+ private final class Interface implements IBinder.DeathRecipient,
+ IBinder.FrozenStateChangeCallback {
+ final IBinder mBinder;
+ final E mInterface;
+ final Object mCookie;
+ final Queue<Consumer<E>> mCallbackQueue;
+ int mCurrentState = IBinder.FrozenStateChangeCallback.STATE_UNFROZEN;
+
+ Interface(E callbackInterface, Object cookie) {
+ mBinder = callbackInterface.asBinder();
+ mInterface = callbackInterface;
mCookie = cookie;
+ mCallbackQueue = mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_ALL
+ || mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT
+ ? new ConcurrentLinkedQueue<>() : null;
+ }
+
+ @Override
+ public synchronized void onFrozenStateChanged(@NonNull IBinder who, int state) {
+ if (state == STATE_UNFROZEN && mCallbackQueue != null) {
+ while (!mCallbackQueue.isEmpty()) {
+ Consumer<E> callback = mCallbackQueue.poll();
+ callback.accept(mInterface);
+ }
+ }
+ mCurrentState = state;
+ }
+
+ void addCallback(@NonNull Consumer<E> callback) {
+ if (mFrozenCalleePolicy == FROZEN_CALLEE_POLICY_UNSET) {
+ callback.accept(mInterface);
+ return;
+ }
+ synchronized (this) {
+ if (mCurrentState == STATE_UNFROZEN) {
+ callback.accept(mInterface);
+ return;
+ }
+ switch (mFrozenCalleePolicy) {
+ case FROZEN_CALLEE_POLICY_ENQUEUE_ALL:
+ if (mCallbackQueue.size() >= mMaxQueueSize) {
+ mCallbackQueue.poll();
+ }
+ mCallbackQueue.offer(callback);
+ break;
+ case FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT:
+ mCallbackQueue.clear();
+ mCallbackQueue.offer(callback);
+ break;
+ case FROZEN_CALLEE_POLICY_DROP:
+ // Do nothing. Just ignore the callback.
+ break;
+ case FROZEN_CALLEE_POLICY_UNSET:
+ // Do nothing. Should have returned at the start of the method.
+ break;
+ }
+ }
+ }
+
+ void maybeSubscribeToFrozenCallback() throws RemoteException {
+ if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+ try {
+ mBinder.addFrozenStateChangeCallback(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
+ // ignoring the error and moving on. mCurrentState would always be
+ // STATE_UNFROZEN and all callbacks are invoked immediately.
+ }
+ }
+ }
+
+ void maybeUnsubscribeFromFrozenCallback() {
+ if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+ try {
+ mBinder.removeFrozenStateChangeCallback(this);
+ } catch (UnsupportedOperationException e) {
+ // The kernel does not support frozen notifications. Ignore the error and move
+ // on.
+ }
+ }
}
public void binderDied() {
- synchronized (mCallbacks) {
- mCallbacks.remove(mCallback.asBinder());
+ synchronized (mInterfaces) {
+ mInterfaces.remove(mBinder);
+ maybeUnsubscribeFromFrozenCallback();
}
- onCallbackDied(mCallback, mCookie);
+ onCallbackDied(mInterface, mCookie);
}
}
/**
+ * Builder for {@link RemoteCallbackList}.
+ *
+ * @param <E> The remote callback interface type.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public static final class Builder<E extends IInterface> {
+ private @FrozenCalleePolicy int mFrozenCalleePolicy;
+ private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
+ private InterfaceDiedCallback mInterfaceDiedCallback;
+
+ /**
+ * Creates a Builder for {@link RemoteCallbackList}.
+ *
+ * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
+ * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
+ * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
+ * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
+ */
+ public Builder(@FrozenCalleePolicy int frozenCalleePolicy) {
+ mFrozenCalleePolicy = frozenCalleePolicy;
+ }
+
+ /**
+ * Sets the max queue size.
+ *
+ * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
+ * recipient's process is frozen. Once the limit is reached, the oldest callback is dropped
+ * to keep the size under the limit. Should only be called for
+ * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
+ *
+ * @return This builder.
+ * @throws IllegalArgumentException if the maxQueueSize is not positive.
+ * @throws UnsupportedOperationException if frozenCalleePolicy is not
+ * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
+ */
+ public @NonNull Builder setMaxQueueSize(int maxQueueSize) {
+ if (maxQueueSize <= 0) {
+ throw new IllegalArgumentException("maxQueueSize must be positive");
+ }
+ if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_ENQUEUE_ALL) {
+ throw new UnsupportedOperationException(
+ "setMaxQueueSize can only be called for FROZEN_CALLEE_POLICY_ENQUEUE_ALL");
+ }
+ mMaxQueueSize = maxQueueSize;
+ return this;
+ }
+
+ /**
+ * Sets the callback to be invoked when an interface dies.
+ */
+ public @NonNull Builder setInterfaceDiedCallback(
+ @NonNull InterfaceDiedCallback<E> callback) {
+ mInterfaceDiedCallback = callback;
+ return this;
+ }
+
+ /**
+ * For notifying when the process hosting a callback interface has died.
+ *
+ * @param <E> The remote callback interface type.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public interface InterfaceDiedCallback<E extends IInterface> {
+ /**
+ * Invoked when a callback interface has died.
+ *
+ * @param remoteCallbackList the list that the interface was registered with.
+ * @param deadInterface the interface that has died.
+ * @param cookie the cookie specified on interface registration.
+ */
+ void onInterfaceDied(@NonNull RemoteCallbackList<E> remoteCallbackList,
+ E deadInterface, @Nullable Object cookie);
+ }
+
+ /**
+ * Builds and returns a {@link RemoteCallbackList}.
+ *
+ * @return The built {@link RemoteCallbackList} object.
+ */
+ public @NonNull RemoteCallbackList<E> build() {
+ if (mInterfaceDiedCallback != null) {
+ return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize) {
+ @Override
+ public void onCallbackDied(E deadInterface, Object cookie) {
+ mInterfaceDiedCallback.onInterfaceDied(this, deadInterface, cookie);
+ }
+ };
+ }
+ return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize);
+ }
+ }
+
+ /**
+ * Returns the frozen callee policy.
+ *
+ * @return The frozen callee policy.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public @FrozenCalleePolicy int getFrozenCalleePolicy() {
+ return mFrozenCalleePolicy;
+ }
+
+ /**
+ * Returns the max queue size.
+ *
+ * @return The max queue size.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public int getMaxQueueSize() {
+ return mMaxQueueSize;
+ }
+
+ /**
+ * Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to
+ * <pre>
+ * new RemoteCallbackList.Build(RemoteCallbackList.FROZEN_CALLEE_POLICY_UNSET).build()
+ * </pre>
+ */
+ public RemoteCallbackList() {
+ this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE);
+ }
+
+ /**
+ * Creates a RemoteCallbackList with the specified frozen callee policy.
+ *
+ * @param frozenCalleePolicy When the callback recipient's process is frozen, this parameter
+ * specifies when/whether callbacks are invoked. It's important to choose a strategy that's
+ * right for the use case. Leaving the policy unset with {@link #FROZEN_CALLEE_POLICY_UNSET}
+ * is not recommended as it allows callbacks to be invoked while the recipient is frozen.
+ *
+ * @param maxQueueSize The max size limit on the queue that stores callbacks added when the
+ * 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}.
+ */
+ private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize) {
+ mFrozenCalleePolicy = frozenCalleePolicy;
+ mMaxQueueSize = maxQueueSize;
+ }
+
+ /**
* Simple version of {@link RemoteCallbackList#register(E, Object)}
* that does not take a cookie object.
*/
- public boolean register(E callback) {
- return register(callback, null);
+ public boolean register(E callbackInterface) {
+ return register(callbackInterface, null);
}
/**
- * Add a new callback to the list. This callback will remain in the list
+ * Add a new interface to the list. This interface will remain in the list
* until a corresponding call to {@link #unregister} or its hosting process
- * goes away. If the callback was already registered (determined by
- * checking to see if the {@link IInterface#asBinder callback.asBinder()}
- * object is already in the list), then it will be left as-is.
+ * goes away. If the interface was already registered (determined by
+ * checking to see if the {@link IInterface#asBinder callbackInterface.asBinder()}
+ * object is already in the list), then it will be replaced with the new interface.
* Registrations are not counted; a single call to {@link #unregister}
- * will remove a callback after any number calls to register it.
+ * will remove an interface after any number calls to register it.
*
- * @param callback The callback interface to be added to the list. Must
+ * @param callbackInterface The callback interface to be added to the list. Must
* not be null -- passing null here will cause a NullPointerException.
* Most services will want to check for null before calling this with
* an object given from a client, so that clients can't crash the
* service with bad data.
*
* @param cookie Optional additional data to be associated with this
- * callback.
- *
- * @return Returns true if the callback was successfully added to the list.
+ * interface.
+ *
+ * @return Returns true if the interface was successfully added to the list.
* Returns false if it was not added, either because {@link #kill} had
- * previously been called or the callback's process has gone away.
+ * previously been called or the interface's process has gone away.
*
* @see #unregister
* @see #kill
* @see #onCallbackDied
*/
- public boolean register(E callback, Object cookie) {
- synchronized (mCallbacks) {
+ public boolean register(E callbackInterface, Object cookie) {
+ synchronized (mInterfaces) {
if (mKilled) {
return false;
}
// Flag unusual case that could be caused by a leak. b/36778087
- logExcessiveCallbacks();
- IBinder binder = callback.asBinder();
+ logExcessiveInterfaces();
+ IBinder binder = callbackInterface.asBinder();
try {
- Callback cb = new Callback(callback, cookie);
- unregister(callback);
- binder.linkToDeath(cb, 0);
- mCallbacks.put(binder, cb);
+ Interface i = new Interface(callbackInterface, cookie);
+ unregister(callbackInterface);
+ binder.linkToDeath(i, 0);
+ i.maybeSubscribeToFrozenCallback();
+ mInterfaces.put(binder, i);
return true;
} catch (RemoteException e) {
return false;
@@ -136,27 +424,28 @@
}
/**
- * Remove from the list a callback that was previously added with
+ * Remove from the list an interface that was previously added with
* {@link #register}. This uses the
- * {@link IInterface#asBinder callback.asBinder()} object to correctly
+ * {@link IInterface#asBinder callbackInterface.asBinder()} object to correctly
* find the previous registration.
* Registrations are not counted; a single unregister call will remove
- * a callback after any number calls to {@link #register} for it.
+ * an interface after any number calls to {@link #register} for it.
*
- * @param callback The callback to be removed from the list. Passing
+ * @param callbackInterface The interface to be removed from the list. Passing
* null here will cause a NullPointerException, so you will generally want
* to check for null before calling.
*
- * @return Returns true if the callback was found and unregistered. Returns
- * false if the given callback was not found on the list.
+ * @return Returns true if the interface was found and unregistered. Returns
+ * false if the given interface was not found on the list.
*
* @see #register
*/
- public boolean unregister(E callback) {
- synchronized (mCallbacks) {
- Callback cb = mCallbacks.remove(callback.asBinder());
- if (cb != null) {
- cb.mCallback.asBinder().unlinkToDeath(cb, 0);
+ public boolean unregister(E callbackInterface) {
+ synchronized (mInterfaces) {
+ Interface i = mInterfaces.remove(callbackInterface.asBinder());
+ if (i != null) {
+ i.mInterface.asBinder().unlinkToDeath(i, 0);
+ i.maybeUnsubscribeFromFrozenCallback();
return true;
}
return false;
@@ -164,20 +453,21 @@
}
/**
- * Disable this callback list. All registered callbacks are unregistered,
+ * Disable this interface list. All registered interfaces are unregistered,
* and the list is disabled so that future calls to {@link #register} will
* fail. This should be used when a Service is stopping, to prevent clients
- * from registering callbacks after it is stopped.
+ * from registering interfaces after it is stopped.
*
* @see #register
*/
public void kill() {
- synchronized (mCallbacks) {
- for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) {
- Callback cb = mCallbacks.valueAt(cbi);
- cb.mCallback.asBinder().unlinkToDeath(cb, 0);
+ synchronized (mInterfaces) {
+ for (int cbi = mInterfaces.size() - 1; cbi >= 0; cbi--) {
+ Interface i = mInterfaces.valueAt(cbi);
+ i.mInterface.asBinder().unlinkToDeath(i, 0);
+ i.maybeUnsubscribeFromFrozenCallback();
}
- mCallbacks.clear();
+ mInterfaces.clear();
mKilled = true;
}
}
@@ -186,15 +476,15 @@
* Old version of {@link #onCallbackDied(E, Object)} that
* does not provide a cookie.
*/
- public void onCallbackDied(E callback) {
+ public void onCallbackDied(E callbackInterface) {
}
/**
- * Called when the process hosting a callback in the list has gone away.
+ * Called when the process hosting an interface in the list has gone away.
* The default implementation calls {@link #onCallbackDied(E)}
* for backwards compatibility.
*
- * @param callback The callback whose process has died. Note that, since
+ * @param callbackInterface The interface whose process has died. Note that, since
* its process has died, you can not make any calls on to this interface.
* You can, however, retrieve its IBinder and compare it with another
* IBinder to see if it is the same object.
@@ -203,13 +493,15 @@
*
* @see #register
*/
- public void onCallbackDied(E callback, Object cookie) {
- onCallbackDied(callback);
+ public void onCallbackDied(E callbackInterface, Object cookie) {
+ onCallbackDied(callbackInterface);
}
/**
- * Prepare to start making calls to the currently registered callbacks.
- * This creates a copy of the callback list, which you can retrieve items
+ * Use {@link #broadcast(Consumer)} instead to ensure proper handling of frozen processes.
+ *
+ * Prepare to start making calls to the currently registered interfaces.
+ * This creates a copy of the interface list, which you can retrieve items
* from using {@link #getBroadcastItem}. Note that only one broadcast can
* be active at a time, so you must be sure to always call this from the
* same thread (usually by scheduling with {@link Handler}) or
@@ -219,44 +511,56 @@
* <p>A typical loop delivering a broadcast looks like this:
*
* <pre>
- * int i = callbacks.beginBroadcast();
+ * int i = interfaces.beginBroadcast();
* while (i > 0) {
* i--;
* try {
- * callbacks.getBroadcastItem(i).somethingHappened();
+ * interfaces.getBroadcastItem(i).somethingHappened();
* } catch (RemoteException e) {
* // The RemoteCallbackList will take care of removing
* // the dead object for us.
* }
* }
- * callbacks.finishBroadcast();</pre>
+ * interfaces.finishBroadcast();</pre>
*
- * @return Returns the number of callbacks in the broadcast, to be used
+ * Note that this method is only supported for {@link #FROZEN_CALLEE_POLICY_UNSET}. For other
+ * policies use {@link #broadcast(Consumer)} instead.
+ *
+ * @return Returns the number of interfaces in the broadcast, to be used
* with {@link #getBroadcastItem} to determine the range of indices you
* can supply.
*
+ * @throws UnsupportedOperationException if an frozen callee policy is set.
+ *
* @see #getBroadcastItem
* @see #finishBroadcast
*/
public int beginBroadcast() {
- synchronized (mCallbacks) {
+ if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+ throw new UnsupportedOperationException();
+ }
+ return beginBroadcastInternal();
+ }
+
+ private int beginBroadcastInternal() {
+ synchronized (mInterfaces) {
if (mBroadcastCount > 0) {
throw new IllegalStateException(
"beginBroadcast() called while already in a broadcast");
}
- final int N = mBroadcastCount = mCallbacks.size();
- if (N <= 0) {
+ final int n = mBroadcastCount = mInterfaces.size();
+ if (n <= 0) {
return 0;
}
Object[] active = mActiveBroadcast;
- if (active == null || active.length < N) {
- mActiveBroadcast = active = new Object[N];
+ if (active == null || active.length < n) {
+ mActiveBroadcast = active = new Object[n];
}
- for (int i=0; i<N; i++) {
- active[i] = mCallbacks.valueAt(i);
+ for (int i = 0; i < n; i++) {
+ active[i] = mInterfaces.valueAt(i);
}
- return N;
+ return n;
}
}
@@ -267,24 +571,23 @@
* calling {@link #finishBroadcast}.
*
* <p>Note that it is possible for the process of one of the returned
- * callbacks to go away before you call it, so you will need to catch
+ * interfaces to go away before you call it, so you will need to catch
* {@link RemoteException} when calling on to the returned object.
- * The callback list itself, however, will take care of unregistering
+ * The interface list itself, however, will take care of unregistering
* these objects once it detects that it is no longer valid, so you can
* handle such an exception by simply ignoring it.
*
- * @param index Which of the registered callbacks you would like to
+ * @param index Which of the registered interfaces you would like to
* retrieve. Ranges from 0 to {@link #beginBroadcast}-1, inclusive.
*
- * @return Returns the callback interface that you can call. This will
- * always be non-null.
+ * @return Returns the interface that you can call. This will always be non-null.
*
* @see #beginBroadcast
*/
public E getBroadcastItem(int index) {
- return ((Callback)mActiveBroadcast[index]).mCallback;
+ return ((Interface) mActiveBroadcast[index]).mInterface;
}
-
+
/**
* Retrieve the cookie associated with the item
* returned by {@link #getBroadcastItem(int)}.
@@ -292,7 +595,7 @@
* @see #getBroadcastItem
*/
public Object getBroadcastCookie(int index) {
- return ((Callback)mActiveBroadcast[index]).mCookie;
+ return ((Interface) mActiveBroadcast[index]).mCookie;
}
/**
@@ -303,7 +606,7 @@
* @see #beginBroadcast
*/
public void finishBroadcast() {
- synchronized (mCallbacks) {
+ synchronized (mInterfaces) {
if (mBroadcastCount < 0) {
throw new IllegalStateException(
"finishBroadcast() called outside of a broadcast");
@@ -322,16 +625,18 @@
}
/**
- * Performs {@code action} on each callback, calling
- * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
+ * Performs {@code callback} on each registered interface.
*
- * @hide
+ * This is equivalent to #beginBroadcast, followed by iterating over the items using
+ * #getBroadcastItem and then @finishBroadcast, except that this method supports
+ * frozen callee policies.
*/
- public void broadcast(Consumer<E> action) {
- int itemCount = beginBroadcast();
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ public void broadcast(@NonNull Consumer<E> callback) {
+ int itemCount = beginBroadcastInternal();
try {
for (int i = 0; i < itemCount; i++) {
- action.accept(getBroadcastItem(i));
+ ((Interface) mActiveBroadcast[i]).addCallback(callback);
}
} finally {
finishBroadcast();
@@ -339,16 +644,16 @@
}
/**
- * Performs {@code action} for each cookie associated with a callback, calling
+ * Performs {@code callback} for each cookie associated with an interface, calling
* {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
*
* @hide
*/
- public <C> void broadcastForEachCookie(Consumer<C> action) {
+ public <C> void broadcastForEachCookie(Consumer<C> callback) {
int itemCount = beginBroadcast();
try {
for (int i = 0; i < itemCount; i++) {
- action.accept((C) getBroadcastCookie(i));
+ callback.accept((C) getBroadcastCookie(i));
}
} finally {
finishBroadcast();
@@ -356,16 +661,16 @@
}
/**
- * Performs {@code action} on each callback and associated cookie, calling {@link
+ * Performs {@code callback} on each interface and associated cookie, calling {@link
* #beginBroadcast()}/{@link #finishBroadcast()} before/after looping.
*
* @hide
*/
- public <C> void broadcast(BiConsumer<E, C> action) {
+ public <C> void broadcast(BiConsumer<E, C> callback) {
int itemCount = beginBroadcast();
try {
for (int i = 0; i < itemCount; i++) {
- action.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
+ callback.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
}
} finally {
finishBroadcast();
@@ -373,10 +678,10 @@
}
/**
- * Returns the number of registered callbacks. Note that the number of registered
- * callbacks may differ from the value returned by {@link #beginBroadcast()} since
- * the former returns the number of callbacks registered at the time of the call
- * and the second the number of callback to which the broadcast will be delivered.
+ * Returns the number of registered interfaces. Note that the number of registered
+ * interfaces may differ from the value returned by {@link #beginBroadcast()} since
+ * the former returns the number of interfaces registered at the time of the call
+ * and the second the number of interfaces to which the broadcast will be delivered.
* <p>
* This function is useful to decide whether to schedule a broadcast if this
* requires doing some work which otherwise would not be performed.
@@ -385,39 +690,39 @@
* @return The size.
*/
public int getRegisteredCallbackCount() {
- synchronized (mCallbacks) {
+ synchronized (mInterfaces) {
if (mKilled) {
return 0;
}
- return mCallbacks.size();
+ return mInterfaces.size();
}
}
/**
- * Return a currently registered callback. Note that this is
+ * Return a currently registered interface. Note that this is
* <em>not</em> the same as {@link #getBroadcastItem} and should not be used
- * interchangeably with it. This method returns the registered callback at the given
+ * interchangeably with it. This method returns the registered interface at the given
* index, not the current broadcast state. This means that it is not itself thread-safe:
* any call to {@link #register} or {@link #unregister} will change these indices, so you
* must do your own thread safety between these to protect from such changes.
*
- * @param index Index of which callback registration to return, from 0 to
+ * @param index Index of which interface registration to return, from 0 to
* {@link #getRegisteredCallbackCount()} - 1.
*
- * @return Returns whatever callback is associated with this index, or null if
+ * @return Returns whatever interface is associated with this index, or null if
* {@link #kill()} has been called.
*/
public E getRegisteredCallbackItem(int index) {
- synchronized (mCallbacks) {
+ synchronized (mInterfaces) {
if (mKilled) {
return null;
}
- return mCallbacks.valueAt(index).mCallback;
+ return mInterfaces.valueAt(index).mInterface;
}
}
/**
- * Return any cookie associated with a currently registered callback. Note that this is
+ * Return any cookie associated with a currently registered interface. Note that this is
* <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
* interchangeably with it. This method returns the current cookie registered at the given
* index, not the current broadcast state. This means that it is not itself thread-safe:
@@ -431,25 +736,25 @@
* {@link #kill()} has been called.
*/
public Object getRegisteredCallbackCookie(int index) {
- synchronized (mCallbacks) {
+ synchronized (mInterfaces) {
if (mKilled) {
return null;
}
- return mCallbacks.valueAt(index).mCookie;
+ return mInterfaces.valueAt(index).mCookie;
}
}
/** @hide */
public void dump(PrintWriter pw, String prefix) {
- synchronized (mCallbacks) {
- pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
+ synchronized (mInterfaces) {
+ pw.print(prefix); pw.print("callbacks: "); pw.println(mInterfaces.size());
pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
}
}
- private void logExcessiveCallbacks() {
- final long size = mCallbacks.size();
+ private void logExcessiveInterfaces() {
+ final long size = mInterfaces.size();
final long TOO_MANY = 3000;
final long MAX_CHARS = 1000;
if (size >= TOO_MANY) {
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 3f4f790..5d1d758 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -115,6 +115,14 @@
}
flag {
+ name: "protect_device_config_flags"
+ namespace: "psap_ai"
+ description: "Feature flag to limit adb shell to allowlisted flags"
+ bug: "364083026"
+ is_fixed_read_only: true
+}
+
+flag {
name: "keystore_grant_api"
namespace: "hardware_backed_security"
description: "Feature flag for exposing KeyStore grant APIs"
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 4cc9041..4369cb0 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -33,6 +33,7 @@
#include <algorithm>
#include <array>
+#include <cctype>
#include <cstring>
#include <limits>
#include <memory>
@@ -1004,6 +1005,8 @@
}
}
if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
+ std::replace_if(buffer+start, buffer+end,
+ [](unsigned char c){ return !std::isprint(c); }, '?');
jstring str = env->NewStringUTF(buffer+start);
env->SetObjectArrayElement(outStrings, di, str);
}
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
index 6149382..4620cb8 100644
--- a/core/tests/coretests/src/android/os/OWNERS
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -12,3 +12,6 @@
# Caching
per-file IpcDataCache* = file:/PERFORMANCE_OWNERS
+
+# RemoteCallbackList
+per-file RemoteCallbackListTest.java = shayba@google.com
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index c25f77b..79a0607 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -89,12 +89,12 @@
method public void onBootFinished(int);
method public void onBootStarted();
method public void onCardEmulationActivated(boolean);
- method public void onDisable(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onDisableFinished(int);
+ method public void onDisableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onDisableStarted();
method public void onEeListenActivated(boolean);
- method public void onEnable(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onEnableFinished(int);
+ method public void onEnableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onEnableStarted();
method public void onGetOemAppSearchIntent(@NonNull java.util.List<java.lang.String>, @NonNull java.util.function.Consumer<android.content.Intent>);
method public void onHceEventReceived(int);
@@ -183,6 +183,12 @@
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void recoverRoutingTable(@NonNull android.app.Activity);
+ method @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setServiceEnabledForCategoryOther(@NonNull android.content.ComponentName, boolean);
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; // 0x3
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; // 0x1
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; // 0x2
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; // 0x4
+ field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; // 0x0
}
}
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 5e2e92d..633d8bf 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -47,7 +47,7 @@
boolean unsetPreferredService();
boolean supportsAidPrefixRegistration();
ApduServiceInfo getPreferredPaymentService(int userHandle);
- boolean setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
+ int setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
boolean isDefaultPaymentRegistered();
void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg);
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 57ee981..c677cd6 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -27,7 +27,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
@@ -233,8 +232,7 @@
* {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
* false if NFC cannot be enabled at this time.
*/
- @SuppressLint("MethodNameTense")
- void onEnable(@NonNull Consumer<Boolean> isAllowed);
+ void onEnableRequested(@NonNull Consumer<Boolean> isAllowed);
/**
* Method to check if Nfc is allowed to be disabled by OEMs.
* @param isAllowed The {@link Consumer} to be completed. If disabling NFC is allowed,
@@ -242,7 +240,7 @@
* {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
* false if NFC cannot be disabled at this time.
*/
- void onDisable(@NonNull Consumer<Boolean> isAllowed);
+ void onDisableRequested(@NonNull Consumer<Boolean> isAllowed);
/**
* Callback to indicate that Nfc starts to boot.
@@ -255,7 +253,7 @@
void onEnableStarted();
/**
- * Callback to indicate that Nfc starts to enable.
+ * Callback to indicate that Nfc starts to disable.
*/
void onDisableStarted();
@@ -799,13 +797,13 @@
public void onEnable(ResultReceiver isAllowed) throws RemoteException {
mCallbackMap.forEach((cb, ex) ->
handleVoidCallback(
- new ReceiverWrapper<>(isAllowed), cb::onEnable, ex));
+ new ReceiverWrapper<>(isAllowed), cb::onEnableRequested, ex));
}
@Override
public void onDisable(ResultReceiver isAllowed) throws RemoteException {
mCallbackMap.forEach((cb, ex) ->
handleVoidCallback(
- new ReceiverWrapper<>(isAllowed), cb::onDisable, ex));
+ new ReceiverWrapper<>(isAllowed), cb::onDisableRequested, ex));
}
@Override
public void onBootStarted() throws RemoteException {
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index eb28c3b..8917524 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -185,6 +185,65 @@
@FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET = -1;
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * succeeded.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_OK = 0;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to the unsupported feature.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to the invalid service.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to the service is already set to the requested status.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3;
+
+ /**
+ * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * failed due to unknown error.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4;
+
+ /**
+ * Status code returned by {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+ * @hide
+ */
+ @IntDef(prefix = "SET_SERVICE_ENABLED_STATUS_", value = {
+ SET_SERVICE_ENABLED_STATUS_OK,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET,
+ SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SetServiceEnabledStatusCode {}
+
static boolean sIsInitialized = false;
static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
static INfcCardEmulation sService;
@@ -883,22 +942,24 @@
}
/**
- * Allows to set or unset preferred service (category other) to avoid AID Collision.
+ * Allows to set or unset preferred service (category other) to avoid AID Collision. The user
+ * should use corresponding context using {@link Context#createContextAsUser(UserHandle, int)}
*
* @param service The ComponentName of the service
* @param status true to enable, false to disable
- * @param userId the user handle of the user whose information is being requested.
- * @return set service for the category and true if service is already set return false.
+ * @return true if preferred service is successfully set or unset, otherwise return false.
*
* @hide
*/
- public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status,
- int userId) {
- if (service == null) {
- throw new NullPointerException("activity or service or category is null");
- }
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @SetServiceEnabledStatusCode
+ public int setServiceEnabledForCategoryOther(@NonNull ComponentName service,
+ boolean status) {
return callServiceReturn(() ->
- sService.setServiceEnabledForCategoryOther(userId, service, status), false);
+ sService.setServiceEnabledForCategoryOther(mContext.getUser().getIdentifier(),
+ service, status), SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR);
}
/** @hide */
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 34f0200..8a37aa2 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -173,3 +173,11 @@
description: "Share wallet role routing priority with associated services"
bug: "366243361"
}
+
+flag {
+ name: "nfc_set_service_enabled_for_category_other"
+ is_exported: true
+ namespace: "nfc"
+ description: "Enable set service enabled for category other"
+ bug: "338157113"
+}
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 177f86b..c3ecff4 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -11,3 +11,4 @@
cbrubaker@google.com
omakoto@google.com
michaelwr@google.com
+ronish@google.com
diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
index fe2269a..27c5ea1 100755
--- a/ravenwood/scripts/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/run-ravenwood-tests.sh
@@ -33,7 +33,7 @@
exclude_re=""
smoke_exclude_re=""
dry_run=""
-while getopts "sx:f:dt" opt; do
+while getopts "sx:f:dtb" opt; do
case "$opt" in
s)
# Remove slow tests.
@@ -52,8 +52,13 @@
dry_run="echo"
;;
t)
+ # Redirect log to terminal
export RAVENWOOD_LOG_OUT=$(tty)
;;
+ b)
+ # Build only
+ ATEST=m
+ ;;
'?')
exit 1
;;
@@ -99,11 +104,16 @@
# Calculate the removed tests.
-diff="$(diff <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') )"
+diff="$(diff <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') | grep -v [0-9] )"
if [[ "$diff" != "" ]]; then
echo "Excluded tests:"
echo "$diff"
fi
-$dry_run ${ATEST:-atest} "${targets[@]}"
+run() {
+ echo "Running: ${@}"
+ "${@}"
+}
+
+run $dry_run ${ATEST:-atest} "${targets[@]}"
diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS
index 9439eaa..9f0cabf 100644
--- a/services/core/java/com/android/server/display/OWNERS
+++ b/services/core/java/com/android/server/display/OWNERS
@@ -1,5 +1,4 @@
michaelwr@google.com
-dangittik@google.com
hackbod@google.com
ogunwale@google.com
santoscordon@google.com
@@ -7,5 +6,6 @@
wilczynskip@google.com
brup@google.com
petsjonkin@google.com
+olb@google.com
per-file ColorDisplayService.java=christyfranks@google.com