Merge "Ensure Autofill save dialog buttons are always visible when text is long + display/font size is large" into main
diff --git a/api/Android.bp b/api/Android.bp
index 27c372a..a148cbd 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -200,7 +200,7 @@
out: ["current.srcjar"],
cmd: "$(location merge_zips) $(out) $(in)",
srcs: [
- ":api-stubs-docs-non-updatable",
+ ":api-stubs-docs-non-updatable{.exportable}",
":all-modules-public-stubs-source",
],
visibility: ["//visibility:private"], // Used by make module in //development, mind
diff --git a/core/api/current.txt b/core/api/current.txt
index cb937d2..2e3fe5b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -27305,6 +27305,24 @@
field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_AD_BUFFER = "ad_buffer";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_AD_RESPONSE = "ad_response";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_BROADCAST_INFO_RESPONSE = "broadcast_info_response";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_CHANNEL_URI = "channel_uri";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_TRACKS = "tracks";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_TRACK_ID = "track_id";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_TRACK_TYPE = "track_type";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_TV_MESSAGE_TYPE = "tv_message_type";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_KEY_VIDEO_UNAVAILABLE_REASON = "video_unavailable_reason";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_AD_BUFFER_CONSUMED = "ad_buffer_consumed";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_AD_RESPONSE = "ad_response";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_BROADCAST_INFO_RESPONSE = "broadcast_info_response";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_TRACKS_CHANGED = "tracks_changed";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_TRACK_SELECTED = "track_selected";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_TUNED = "tuned";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_TV_MESSAGE = "tv_message";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_VIDEO_AVAILABLE = "video_available";
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String SESSION_DATA_TYPE_VIDEO_UNAVAILABLE = "video_unavailable";
field public static final int SIGNAL_STRENGTH_LOST = 1; // 0x1
field public static final int SIGNAL_STRENGTH_STRONG = 3; // 0x3
field public static final int SIGNAL_STRENGTH_WEAK = 2; // 0x2
@@ -27456,8 +27474,10 @@
method public boolean onTrackballEvent(android.view.MotionEvent);
method public abstract boolean onTune(android.net.Uri);
method public boolean onTune(android.net.Uri, android.os.Bundle);
+ method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void onTvAdSessionData(@NonNull String, @NonNull android.os.Bundle);
method public void onTvMessage(int, @NonNull android.os.Bundle);
method public void onUnblockContent(android.media.tv.TvContentRating);
+ method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void sendTvInputSessionData(@NonNull String, @NonNull android.os.Bundle);
method public void setOverlayViewEnabled(boolean);
}
@@ -27641,6 +27661,16 @@
@FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public class TvAdManager {
method @NonNull public java.util.List<android.media.tv.ad.TvAdServiceInfo> getTvAdServiceList();
+ method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.ad.TvAdManager.TvAdServiceCallback);
+ method public void unregisterCallback(@NonNull android.media.tv.ad.TvAdManager.TvAdServiceCallback);
+ field public static final String SESSION_DATA_KEY_AD_BUFFER = "ad_buffer";
+ field public static final String SESSION_DATA_KEY_AD_REQUEST = "ad_request";
+ field public static final String SESSION_DATA_KEY_BROADCAST_INFO_REQUEST = "broadcast_info_request";
+ field public static final String SESSION_DATA_KEY_REQUEST_ID = "request_id";
+ field public static final String SESSION_DATA_TYPE_AD_BUFFER_READY = "ad_buffer_ready";
+ field public static final String SESSION_DATA_TYPE_AD_REQUEST = "ad_request";
+ field public static final String SESSION_DATA_TYPE_BROADCAST_INFO_REQUEST = "broadcast_info_request";
+ field public static final String SESSION_DATA_TYPE_REMOVE_BROADCAST_INFO_REQUEST = "remove_broadcast_info_request";
}
public abstract static class TvAdManager.TvAdServiceCallback {
@@ -27660,17 +27690,26 @@
public abstract static class TvAdService.Session implements android.view.KeyEvent.Callback {
ctor public TvAdService.Session(@NonNull android.content.Context);
+ method public boolean isMediaViewEnabled();
method @CallSuper public void layoutSurface(int, int, int, int);
+ method @Nullable public android.view.View onCreateMediaView();
method public boolean onGenericMotionEvent(@NonNull android.view.MotionEvent);
method public boolean onKeyDown(int, @Nullable android.view.KeyEvent);
method public boolean onKeyLongPress(int, @Nullable android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, @Nullable android.view.KeyEvent);
method public boolean onKeyUp(int, @Nullable android.view.KeyEvent);
+ method public void onMediaViewSizeChanged(@Px int, @Px int);
method public abstract void onRelease();
+ method public void onResetAdService();
method public abstract boolean onSetSurface(@Nullable android.view.Surface);
+ method public void onStartAdService();
+ method public void onStopAdService();
method public void onSurfaceChanged(int, int, int);
method public boolean onTouchEvent(@NonNull android.view.MotionEvent);
method public boolean onTrackballEvent(@NonNull android.view.MotionEvent);
+ method public void onTvInputSessionData(@NonNull String, @NonNull android.os.Bundle);
+ method public void sendTvAdSessionData(@NonNull String, @NonNull android.os.Bundle);
+ method @CallSuper public void setMediaViewEnabled(boolean);
}
@FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public final class TvAdServiceInfo implements android.os.Parcelable {
@@ -27687,12 +27726,26 @@
ctor public TvAdView(@NonNull android.content.Context);
ctor public TvAdView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
ctor public TvAdView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int);
+ method public void clearOnUnhandledInputEventListener();
+ method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
+ method @Nullable public android.media.tv.ad.TvAdView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
method public void onLayout(boolean, int, int, int, int);
method public void onMeasure(int, int);
+ method public boolean onUnhandledInputEvent(@NonNull android.view.InputEvent);
method public void onVisibilityChanged(@NonNull android.view.View, int);
method public void prepareAdService(@NonNull String, @NonNull String);
+ method public void reset();
+ method public void resetAdService();
+ method public void setOnUnhandledInputEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.ad.TvAdView.OnUnhandledInputEventListener);
+ method public boolean setTvView(@Nullable android.media.tv.TvView);
+ method public void startAdService();
+ method public void stopAdService();
+ }
+
+ public static interface TvAdView.OnUnhandledInputEventListener {
+ method public boolean onUnhandledInputEvent(@NonNull android.view.InputEvent);
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0dbce97..5074ed7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -4588,19 +4588,19 @@
*/
private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
- NoteOpEvent lastAccessEvent = null;
+ NoteOpEvent lastRejectEvent = null;
for (AttributedOpEntry attributionEntry : mAttributedOpEntries.values()) {
- NoteOpEvent lastAttributionAccessEvent = attributionEntry.getLastRejectEvent(
+ NoteOpEvent lastAttributionRejectEvent = attributionEntry.getLastRejectEvent(
fromUidState, toUidState, flags);
- if (lastAccessEvent == null || (lastAttributionAccessEvent != null
- && lastAttributionAccessEvent.getNoteTime()
- > lastAccessEvent.getNoteTime())) {
- lastAccessEvent = lastAttributionAccessEvent;
+ if (lastRejectEvent == null || (lastAttributionRejectEvent != null
+ && lastAttributionRejectEvent.getNoteTime()
+ > lastRejectEvent.getNoteTime())) {
+ lastRejectEvent = lastAttributionRejectEvent;
}
}
- return lastAccessEvent;
+ return lastRejectEvent;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/OWNERS
new file mode 100644
index 0000000..2ff4d90
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/OWNERS
@@ -0,0 +1,4 @@
+# WM shell transition tracing owners
+# Bug component: 1157642
+natanieljr@google.com
+pablogamito@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
index b3e8bd9..fa331af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
@@ -196,14 +196,18 @@
mDataSource.trace(ctx -> {
final ProtoOutputStream os = ctx.newTracePacket();
+ final long mappingsToken = os.start(PerfettoTrace.TracePacket.SHELL_HANDLER_MAPPINGS);
for (Map.Entry<String, Integer> entry : mHandlerMapping.entrySet()) {
final String handler = entry.getKey();
final int handlerId = entry.getValue();
- final long token = os.start(PerfettoTrace.TracePacket.SHELL_HANDLER_MAPPINGS);
+
+ final long mappingEntryToken = os.start(PerfettoTrace.ShellHandlerMappings.MAPPING);
os.write(PerfettoTrace.ShellHandlerMapping.ID, handlerId);
os.write(PerfettoTrace.ShellHandlerMapping.NAME, handler);
- os.end(token);
+ os.end(mappingEntryToken);
+
}
+ os.end(mappingsToken);
ctx.flush();
});
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 672f58b..aed3e60e 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -556,85 +556,85 @@
/**
* Informs the application that the session has been tuned to the given channel.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see SESSION_DATA_KEY_CHANNEL_URI
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_TUNED = "tuned";
/**
* Sends the type and ID of a selected track. This is used to inform the application that a
* specific track is selected.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see SESSION_DATA_KEY_TRACK_TYPE
* @see SESSION_DATA_KEY_TRACK_ID
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_TRACK_SELECTED = "track_selected";
/**
* Sends the list of all audio/video/subtitle tracks.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see SESSION_DATA_KEY_TRACKS
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_TRACKS_CHANGED = "tracks_changed";
/**
* Informs the application that the video is now available for watching.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_VIDEO_AVAILABLE = "video_available";
/**
* Informs the application that the video became unavailable for some reason.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see SESSION_DATA_KEY_VIDEO_UNAVAILABLE_REASON
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_VIDEO_UNAVAILABLE = "video_unavailable";
/**
* Notifies response for broadcast info.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see SESSION_DATA_KEY_BROADCAST_INFO_RESPONSE
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_BROADCAST_INFO_RESPONSE =
"broadcast_info_response";
/**
* Notifies response for advertisement.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see SESSION_DATA_KEY_AD_RESPONSE
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_AD_RESPONSE = "ad_response";
/**
* Notifies the advertisement buffer is consumed.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see SESSION_DATA_KEY_AD_BUFFER
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_AD_BUFFER_CONSUMED = "ad_buffer_consumed";
/**
* Sends the TV message.
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see TvInputService.Session#notifyTvMessage(int, Bundle)
* @see SESSION_DATA_KEY_TV_MESSAGE_TYPE
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_TYPE_TV_MESSAGE = "tv_message";
@@ -657,9 +657,9 @@
*
* <p> Type: android.net.Uri
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_CHANNEL_URI = "channel_uri";
/**
@@ -671,9 +671,9 @@
* <p> Type: Integer
*
* @see TvTrackInfo#getType()
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_TRACK_TYPE = "track_type";
/**
@@ -682,9 +682,9 @@
* <p> Type: String
*
* @see TvTrackInfo#getId()
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_TRACK_ID = "track_id";
/**
@@ -692,9 +692,9 @@
*
* <p> Type: {@code java.util.List<android.media.tv.TvTrackInfo> }
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_TRACKS = "tracks";
/**
@@ -704,9 +704,9 @@
*
* <p> Type: Integer
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_VIDEO_UNAVAILABLE_REASON =
"video_unavailable_reason";
@@ -715,9 +715,9 @@
*
* <p> Type: android.media.tv.BroadcastInfoResponse
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_BROADCAST_INFO_RESPONSE = "broadcast_info_response";
/**
@@ -725,9 +725,9 @@
*
* <p> Type: android.media.tv.AdResponse
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_AD_RESPONSE = "ad_response";
/**
@@ -735,9 +735,9 @@
*
* <p> Type: android.media.tv.AdBuffer
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_AD_BUFFER = "ad_buffer";
/**
@@ -747,9 +747,9 @@
*
* <p> Type: Integer
*
- * @see TvInputService.Session#notifyTvInputSessionData(String, Bundle)
- * @hide
+ * @see TvInputService.Session#sendTvInputSessionData(String, Bundle)
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public static final String SESSION_DATA_KEY_TV_MESSAGE_TYPE = "tv_message_type";
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 6b03041..432e109 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1262,7 +1262,7 @@
}
/**
- * Notifies data related to this session to corresponding linked
+ * Sends data related to this session to corresponding linked
* {@link android.media.tv.ad.TvAdService} object via TvAdView.
*
* <p>Methods like {@link #notifyBroadcastInfoResponse(BroadcastInfoResponse)} sends the
@@ -1272,21 +1272,21 @@
*
* @param type data type
* @param data the related data values
- * @hide
*/
- public void notifyTvInputSessionData(
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
+ public void sendTvInputSessionData(
@NonNull @TvInputManager.SessionDataType String type, @NonNull Bundle data) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
- if (DEBUG) Log.d(TAG, "notifyTvInputSessionData");
+ if (DEBUG) Log.d(TAG, "sendTvInputSessionData");
if (mSessionCallback != null) {
mSessionCallback.onTvInputSessionData(type, data);
}
} catch (RemoteException e) {
- Log.w(TAG, "error in notifyTvInputSessionData", e);
+ Log.w(TAG, "error in sendTvInputSessionData", e);
}
}
});
@@ -1441,10 +1441,10 @@
*
* @param type the type of the data
* @param data a bundle contains the data received
- * @see android.media.tv.ad.TvAdService.Session#notifyTvAdSessionData(String, Bundle)
+ * @see android.media.tv.ad.TvAdService.Session#sendTvAdSessionData(String, Bundle)
* @see android.media.tv.ad.TvAdView#setTvView(TvView)
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
public void onTvAdSessionData(
@NonNull @TvAdManager.SessionDataType String type, @NonNull Bundle data) {
}
diff --git a/media/java/android/media/tv/ad/TvAdManager.java b/media/java/android/media/tv/ad/TvAdManager.java
index f373bed..15ce9fd 100644
--- a/media/java/android/media/tv/ad/TvAdManager.java
+++ b/media/java/android/media/tv/ad/TvAdManager.java
@@ -171,36 +171,32 @@
/**
* Sends an advertisement request to be processed by the related TV input.
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
* @see SESSION_DATA_KEY_AD_REQUEST
- * @hide
*/
public static final String SESSION_DATA_TYPE_AD_REQUEST = "ad_request";
/**
* Notifies the advertisement buffer is ready.
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
* @see SESSION_DATA_KEY_AD_BUFFER
- * @hide
*/
public static final String SESSION_DATA_TYPE_AD_BUFFER_READY = "ad_buffer_ready";
/**
* Sends request for broadcast info.
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
* @see SESSION_DATA_KEY_BROADCAST_INFO_RESQUEST
- * @hide
*/
public static final String SESSION_DATA_TYPE_BROADCAST_INFO_REQUEST = "broadcast_info_request";
/**
* Removes request for broadcast info.
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
* @see SESSION_DATA_KEY_BROADCAST_INFO_REQUEST_ID
- * @hide
*/
public static final String SESSION_DATA_TYPE_REMOVE_BROADCAST_INFO_REQUEST =
"remove_broadcast_info_request";
@@ -220,8 +216,7 @@
*
* <p> Type: android.media.tv.AdRequest
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
- * @hide
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
*/
public static final String SESSION_DATA_KEY_AD_REQUEST = "ad_request";
@@ -230,8 +225,7 @@
*
* <p> Type: android.media.tv.AdBuffer
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
- * @hide
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
*/
public static final String SESSION_DATA_KEY_AD_BUFFER = "ad_buffer";
@@ -240,8 +234,7 @@
*
* <p> Type: android.media.tv.BroadcastInfoRequest
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
- * @hide
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
*/
public static final String SESSION_DATA_KEY_BROADCAST_INFO_REQUEST = "broadcast_info_request";
@@ -250,8 +243,7 @@
*
* <p> Type: Integer
*
- * @see TvAdService.Session#notifyTvAdSessionData(String, Bundle)
- * @hide
+ * @see TvAdService.Session#sendTvAdSessionData(String, Bundle)
*/
public static final String SESSION_DATA_KEY_REQUEST_ID = "request_id";
@@ -510,7 +502,6 @@
*
* @param callback A callback used to monitor status of the TV AD services.
* @param executor A {@link Executor} that the status change will be delivered to.
- * @hide
*/
public void registerCallback(
@CallbackExecutor @NonNull Executor executor,
@@ -526,7 +517,6 @@
* Unregisters the existing {@link TvAdServiceCallback}.
*
* @param callback The existing callback to remove.
- * @hide
*/
public void unregisterCallback(@NonNull final TvAdServiceCallback callback) {
Preconditions.checkNotNull(callback);
diff --git a/media/java/android/media/tv/ad/TvAdService.java b/media/java/android/media/tv/ad/TvAdService.java
index 953b5cf..d7b29d3 100644
--- a/media/java/android/media/tv/ad/TvAdService.java
+++ b/media/java/android/media/tv/ad/TvAdService.java
@@ -199,7 +199,6 @@
*
* @param enable {@code true} if you want to enable the media view. {@code false}
* otherwise.
- * @hide
*/
@CallSuper
public void setMediaViewEnabled(final boolean enable) {
@@ -225,7 +224,6 @@
* Returns {@code true} if media view is enabled, {@code false} otherwise.
*
* @see #setMediaViewEnabled(boolean)
- * @hide
*/
public boolean isMediaViewEnabled() {
return mMediaViewEnabled;
@@ -253,21 +251,18 @@
/**
* Starts TvAdService session.
- * @hide
*/
public void onStartAdService() {
}
/**
* Stops TvAdService session.
- * @hide
*/
public void onStopAdService() {
}
/**
* Resets TvAdService session.
- * @hide
*/
public void onResetAdService() {
}
@@ -618,9 +613,8 @@
*
* @param type the type of the data
* @param data a bundle contains the data received
- * @see android.media.tv.TvInputService.Session#notifyTvAdSessionData(String, Bundle)
+ * @see android.media.tv.TvInputService.Session#sendTvInputSessionData(String, Bundle)
* @see android.media.tv.ad.TvAdView#setTvView(TvView)
- * @hide
*/
public void onTvInputSessionData(
@NonNull @TvInputManager.SessionDataType String type, @NonNull Bundle data) {
@@ -636,7 +630,6 @@
*
* @param width The width of the media view, in pixels.
* @param height The height of the media view, in pixels.
- * @hide
*/
public void onMediaViewSizeChanged(@Px int width, @Px int height) {
}
@@ -646,7 +639,6 @@
* implementation can override this method and return its own view.
*
* @return a view attached to the media window. {@code null} if no media view is created.
- * @hide
*/
@Nullable
public View onCreateMediaView() {
@@ -654,27 +646,26 @@
}
/**
- * Notifies data related to this session to corresponding linked
+ * Sends data related to this session to corresponding linked
* {@link android.media.tv.TvInputService} object via TvView.
*
* @param type data type
* @param data the related data values
* @see TvAdView#setTvView(TvView)
- * @hide
*/
- public void notifyTvAdSessionData(
+ public void sendTvAdSessionData(
@NonNull @TvAdManager.SessionDataType String type, @NonNull Bundle data) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
- if (DEBUG) Log.d(TAG, "notifyTvAdSessionData");
+ if (DEBUG) Log.d(TAG, "sendTvAdSessionData");
if (mSessionCallback != null) {
mSessionCallback.onTvAdSessionData(type, data);
}
} catch (RemoteException e) {
- Log.w(TAG, "error in notifyTvAdSessionData", e);
+ Log.w(TAG, "error in sendTvAdSessionData", e);
}
}
});
diff --git a/media/java/android/media/tv/ad/TvAdView.java b/media/java/android/media/tv/ad/TvAdView.java
index be88506..ee01468 100644
--- a/media/java/android/media/tv/ad/TvAdView.java
+++ b/media/java/android/media/tv/ad/TvAdView.java
@@ -160,7 +160,6 @@
* @param tvView the TvView to be linked to this TvAdView via linking of Sessions. {@code null}
* to unlink the TvView.
* @return {@code true} if it's linked successfully; {@code false} otherwise.
- * @hide
*/
public boolean setTvView(@Nullable TvView tvView) {
if (tvView == null) {
@@ -259,7 +258,6 @@
* Resets this TvAdView to release its resources.
*
* <p>It can be reused by call {@link #prepareAdService(String, String)}.
- * @hide
*/
public void reset() {
if (DEBUG) Log.d(TAG, "reset()");
@@ -362,7 +360,6 @@
*
* @param event The input event.
* @return {@code true} if the event was handled by the view, {@code false} otherwise.
- * @hide
*/
public boolean dispatchUnhandledInputEvent(@NonNull InputEvent event) {
if (mOnUnhandledInputEventListener != null) {
@@ -381,7 +378,6 @@
* @param event The input event.
* @return If you handled the event, return {@code true}. If you want to allow the event to be
* handled by the next receiver, return {@code false}.
- * @hide
*/
public boolean onUnhandledInputEvent(@NonNull InputEvent event) {
return false;
@@ -392,7 +388,6 @@
* by the TV AD service.
*
* @param listener The callback to be invoked when the unhandled input event is received.
- * @hide
*/
public void setOnUnhandledInputEventListener(
@NonNull @CallbackExecutor Executor executor,
@@ -407,7 +402,6 @@
*
* @see #setOnUnhandledInputEventListener(Executor, OnUnhandledInputEventListener)
* @see #clearOnUnhandledInputEventListener()
- * @hide
*/
@Nullable
public OnUnhandledInputEventListener getOnUnhandledInputEventListener() {
@@ -416,7 +410,6 @@
/**
* Clears the {@link OnUnhandledInputEventListener}.
- * @hide
*/
public void clearOnUnhandledInputEventListener() {
mOnUnhandledInputEventListener = null;
@@ -453,7 +446,6 @@
/**
* Starts the AD service.
- * @hide
*/
public void startAdService() {
if (DEBUG) {
@@ -466,7 +458,6 @@
/**
* Stops the AD service.
- * @hide
*/
public void stopAdService() {
if (DEBUG) {
@@ -481,7 +472,6 @@
* Resets the AD service.
*
* <p>This releases the resources of the corresponding {@link TvAdService.Session}.
- * @hide
*/
public void resetAdService() {
if (DEBUG) {
@@ -622,7 +612,6 @@
/**
* Interface definition for a callback to be invoked when the unhandled input event is received.
- * @hide
*/
public interface OnUnhandledInputEventListener {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index 20c8add..6836816 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -238,6 +238,9 @@
) {
val TAG = "AvalancheSuppressor"
+ override var reason: String = "avalanche"
+ protected set
+
enum class State {
ALLOW_CONVERSATION_AFTER_AVALANCHE,
ALLOW_HIGH_PRIORITY_CONVERSATION_ANY_TIME,
@@ -252,13 +255,13 @@
override fun shouldSuppress(entry: NotificationEntry): Boolean {
val timeSinceAvalanche = systemClock.currentTimeMillis() - avalancheProvider.startTime
val isActive = timeSinceAvalanche < avalancheProvider.timeoutMs
- val state = allow(entry)
+ val state = calculateState(entry)
val suppress = isActive && state == State.SUPPRESS
reason = "avalanche suppress=$suppress isActive=$isActive state=$state"
return suppress
}
- fun allow(entry: NotificationEntry): State {
+ private fun calculateState(entry: NotificationEntry): State {
if (
entry.ranking.isConversation &&
entry.sbn.notification.`when` > avalancheProvider.startTime
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
index 2f80c5d..ee79727 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
@@ -85,7 +85,7 @@
/** A reason why visual interruptions might be suppressed based on the notification. */
abstract class VisualInterruptionFilter(
override val types: Set<VisualInterruptionType>,
- override var reason: String,
+ override val reason: String,
override val uiEventId: UiEventEnum? = null,
override val eventLogData: EventLogData? = null
) : VisualInterruptionSuppressor {
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index c37e619..d1c8c30 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -152,6 +152,11 @@
private int mActiveIndex;
/**
+ * True if the broadcast actively being dispatched to this process was re-enqueued previously.
+ */
+ private boolean mActiveReEnqueued;
+
+ /**
* Count of {@link #mActive} broadcasts that have been dispatched since this
* queue was last idle.
*/
@@ -312,6 +317,7 @@
final SomeArgs broadcastArgs = SomeArgs.obtain();
broadcastArgs.arg1 = record;
broadcastArgs.argi1 = recordIndex;
+ broadcastArgs.argi2 = 1;
getQueueForBroadcast(record).addFirst(broadcastArgs);
onBroadcastEnqueued(record, recordIndex);
}
@@ -609,6 +615,7 @@
final SomeArgs next = removeNextBroadcast();
mActive = (BroadcastRecord) next.arg1;
mActiveIndex = next.argi1;
+ mActiveReEnqueued = (next.argi2 == 1);
mActiveCountSinceIdle++;
mActiveAssumedDeliveryCountSinceIdle +=
(mActive.isAssumedDelivered(mActiveIndex) ? 1 : 0);
@@ -624,12 +631,21 @@
public void makeActiveIdle() {
mActive = null;
mActiveIndex = 0;
+ mActiveReEnqueued = false;
mActiveCountSinceIdle = 0;
mActiveAssumedDeliveryCountSinceIdle = 0;
mActiveViaColdStart = false;
invalidateRunnableAt();
}
+ public boolean wasActiveBroadcastReEnqueued() {
+ // If the flag is not enabled, treat as if the broadcast was never re-enqueued.
+ if (!Flags.avoidRepeatedBcastReEnqueues()) {
+ return false;
+ }
+ return mActiveReEnqueued;
+ }
+
/**
* Update summary statistics when the given record has been enqueued.
*/
@@ -1476,6 +1492,9 @@
if (runningOomAdjusted) {
pw.print("runningOomAdjusted:"); pw.println(runningOomAdjusted);
}
+ if (mActiveReEnqueued) {
+ pw.print("activeReEnqueued:"); pw.println(mActiveReEnqueued);
+ }
}
@NeverCompile
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index db0f03f..98263df 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -542,8 +542,8 @@
updateOomAdj |= queue.runningOomAdjusted;
try {
completed = scheduleReceiverWarmLocked(queue);
- } catch (BroadcastDeliveryFailedException e) {
- reEnqueueActiveBroadcast(queue);
+ } catch (BroadcastRetryException e) {
+ finishOrReEnqueueActiveBroadcast(queue);
completed = true;
}
} else {
@@ -586,7 +586,12 @@
private void clearInvalidPendingColdStart() {
logw("Clearing invalid pending cold start: " + mRunningColdStart);
- mRunningColdStart.reEnqueueActiveBroadcast();
+ if (mRunningColdStart.wasActiveBroadcastReEnqueued()) {
+ finishReceiverActiveLocked(mRunningColdStart, BroadcastRecord.DELIVERY_FAILURE,
+ "invalid start with re-enqueued broadcast");
+ } else {
+ mRunningColdStart.reEnqueueActiveBroadcast();
+ }
demoteFromRunningLocked(mRunningColdStart);
clearRunningColdStart();
enqueueUpdateRunningList();
@@ -613,19 +618,26 @@
}
}
- private void reEnqueueActiveBroadcast(@NonNull BroadcastProcessQueue queue) {
+ private void finishOrReEnqueueActiveBroadcast(@NonNull BroadcastProcessQueue queue) {
checkState(queue.isActive(), "isActive");
- final BroadcastRecord record = queue.getActive();
- final int index = queue.getActiveIndex();
- setDeliveryState(queue, queue.app, record, index, record.receivers.get(index),
- BroadcastRecord.DELIVERY_PENDING, "reEnqueueActiveBroadcast");
- queue.reEnqueueActiveBroadcast();
+ if (queue.wasActiveBroadcastReEnqueued()) {
+ // If the broadcast was already re-enqueued previously, finish it to avoid repeated
+ // delivery attempts
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
+ "re-enqueued broadcast delivery failed");
+ } else {
+ final BroadcastRecord record = queue.getActive();
+ final int index = queue.getActiveIndex();
+ setDeliveryState(queue, queue.app, record, index, record.receivers.get(index),
+ BroadcastRecord.DELIVERY_PENDING, "reEnqueueActiveBroadcast");
+ queue.reEnqueueActiveBroadcast();
+ }
}
@Override
public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app)
- throws BroadcastDeliveryFailedException {
+ throws BroadcastRetryException {
if (DEBUG_BROADCAST) {
logv("Process " + app + " is attached");
}
@@ -653,8 +665,8 @@
if (scheduleReceiverWarmLocked(queue)) {
demoteFromRunningLocked(queue);
}
- } catch (BroadcastDeliveryFailedException e) {
- reEnqueueActiveBroadcast(queue);
+ } catch (BroadcastRetryException e) {
+ finishOrReEnqueueActiveBroadcast(queue);
demoteFromRunningLocked(queue);
throw e;
}
@@ -983,7 +995,7 @@
@CheckResult
@GuardedBy("mService")
private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue)
- throws BroadcastDeliveryFailedException {
+ throws BroadcastRetryException {
checkState(queue.isActive(), "isActive");
final int cookie = traceBegin("scheduleReceiverWarmLocked");
@@ -1065,7 +1077,7 @@
*/
@CheckResult
private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue,
- @NonNull BroadcastRecord r, int index) throws BroadcastDeliveryFailedException {
+ @NonNull BroadcastRecord r, int index) throws BroadcastRetryException {
final ProcessRecord app = queue.app;
final Object receiver = r.receivers.get(index);
@@ -1157,7 +1169,7 @@
// to try redelivering the broadcast to this receiver.
if (receiver instanceof ResolveInfo) {
cancelDeliveryTimeoutLocked(queue);
- throw new BroadcastDeliveryFailedException(e);
+ throw new BroadcastRetryException(e);
}
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"remote app");
@@ -1316,8 +1328,8 @@
demoteFromRunningLocked(queue);
return true;
}
- } catch (BroadcastDeliveryFailedException e) {
- reEnqueueActiveBroadcast(queue);
+ } catch (BroadcastRetryException e) {
+ finishOrReEnqueueActiveBroadcast(queue);
demoteFromRunningLocked(queue);
return true;
}
diff --git a/services/core/java/com/android/server/am/BroadcastRetryException.java b/services/core/java/com/android/server/am/BroadcastRetryException.java
new file mode 100644
index 0000000..8bd6664
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastRetryException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.am;
+
+/**
+ * Exception to represent that broadcast delivery failed and we should try redelivering it.
+ */
+public class BroadcastRetryException extends BroadcastDeliveryFailedException {
+ public BroadcastRetryException(String name) {
+ super(name);
+ }
+
+ public BroadcastRetryException(Exception cause) {
+ super(cause);
+ }
+}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 862542e..7d82f0c 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1499,8 +1499,12 @@
&& !uidRec.isCurAllowListed()) {
// UID is now in the background (and not on the temp allowlist). Was it
// previously in the foreground (or on the temp allowlist)?
+ // Or, it wasn't in the foreground / allowlist, but its last background
+ // timestamp is also 0, this means it's never been in the
+ // foreground / allowlist since it's born at all.
if (!ActivityManager.isProcStateBackground(uidRec.getSetProcState())
- || uidRec.isSetAllowListed()) {
+ || uidRec.isSetAllowListed()
+ || uidRec.getLastBackgroundTime() == 0) {
uidRec.setLastBackgroundTime(nowElapsed);
if (mService.mDeterministicUidIdle
|| !mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
@@ -1526,6 +1530,7 @@
uidRec.setIdle(false);
}
uidRec.setLastBackgroundTime(0);
+ uidRec.setLastIdleTime(0);
}
final boolean wasCached = uidRec.getSetProcState()
> ActivityManager.PROCESS_STATE_RECEIVER;
@@ -3700,12 +3705,14 @@
for (int i = N - 1; i >= 0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
final long bgTime = uidRec.getLastBackgroundTime();
- if (bgTime > 0 && !uidRec.isIdle()) {
+ final long idleTime = uidRec.getLastIdleTime();
+ if (bgTime > 0 && (!uidRec.isIdle() || idleTime == 0)) {
if (bgTime <= maxBgTime) {
EventLogTags.writeAmUidIdle(uidRec.getUid());
synchronized (mProcLock) {
uidRec.setIdle(true);
uidRec.setSetIdle(true);
+ uidRec.setLastIdleTime(nowElapsed);
}
mService.doStopUidLocked(uidRec.getUid(), uidRec);
} else {
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 4329afc..45fd470 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -66,6 +66,9 @@
private long mLastBackgroundTime;
@CompositeRWLock({"mService", "mProcLock"})
+ private long mLastIdleTime;
+
+ @CompositeRWLock({"mService", "mProcLock"})
private boolean mEphemeral;
@CompositeRWLock({"mService", "mProcLock"})
@@ -255,6 +258,16 @@
}
@GuardedBy(anyOf = {"mService", "mProcLock"})
+ long getLastIdleTime() {
+ return mLastIdleTime;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ void setLastIdleTime(long lastActiveTime) {
+ mLastIdleTime = lastActiveTime;
+ }
+
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
boolean isEphemeral() {
return mEphemeral;
}
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 31d9cc9..16dbe18 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -42,3 +42,14 @@
description: "Optimize the service bindings by different policies like skipping oom adjuster"
bug: "318717054"
}
+
+flag {
+ namespace: "backstage_power"
+ name: "avoid_repeated_bcast_re_enqueues"
+ description: "Avoid re-enqueueing a broadcast repeatedly"
+ bug: "319225224"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index d928306..9f97551 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -73,6 +73,7 @@
"testng",
"compatibility-device-util-axt",
"flag-junit",
+ "am_flags_lib",
],
libs: [
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
index f875f65..fb47aa8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
@@ -38,6 +38,8 @@
import android.os.HandlerThread;
import android.os.TestLooperManager;
import android.os.UserHandle;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.util.SparseArray;
@@ -93,6 +95,9 @@
.spyStatic(ProcessList.class)
.build();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[1];
@Mock
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 75409d9..3f6117b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -75,6 +75,8 @@
import android.os.PowerExemptionManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.util.proto.ProtoOutputStream;
@@ -135,6 +137,17 @@
ProcessStartBehavior.SUCCESS);
/**
+ * Map of processes to behaviors indicating how the new processes should behave as needed
+ * by the tests.
+ */
+ private ArrayMap<String, ProcessBehavior> mNewProcessBehaviors = new ArrayMap<>();
+
+ /**
+ * Map of processes to behaviors indicating how the new process starts should result in.
+ */
+ private ArrayMap<String, ProcessStartBehavior> mNewProcessStartBehaviors = new ArrayMap<>();
+
+ /**
* Collection of all active processes during current test run.
*/
private List<ProcessRecord> mActiveProcesses = new ArrayList<>();
@@ -161,15 +174,17 @@
Log.v(TAG, "Intercepting startProcessLocked() for "
+ Arrays.toString(invocation.getArguments()));
assertHealth();
- final ProcessStartBehavior behavior = mNextProcessStartBehavior
- .getAndSet(ProcessStartBehavior.SUCCESS);
+ final String processName = invocation.getArgument(0);
+ final ProcessStartBehavior behavior = mNewProcessStartBehaviors.getOrDefault(
+ processName, mNextProcessStartBehavior.getAndSet(ProcessStartBehavior.SUCCESS));
if (behavior == ProcessStartBehavior.FAIL_NULL) {
return null;
}
- final String processName = invocation.getArgument(0);
final ApplicationInfo ai = invocation.getArgument(1);
+ final ProcessBehavior processBehavior = mNewProcessBehaviors.getOrDefault(
+ processName, ProcessBehavior.NORMAL);
final ProcessRecord res = makeActiveProcessRecord(ai, processName,
- ProcessBehavior.NORMAL, UnaryOperator.identity());
+ processBehavior, UnaryOperator.identity());
final ProcessRecord deliverRes;
switch (behavior) {
case SUCCESS_PREDECESSOR:
@@ -274,6 +289,8 @@
assertEquals(app.toShortString(), ProcessList.SCHED_GROUP_UNDEFINED,
mQueue.getPreferredSchedulingGroupLocked(app));
}
+ mNewProcessBehaviors.clear();
+ mNewProcessStartBehaviors.clear();
}
@Override
@@ -955,6 +972,40 @@
}
/**
+ * Verify that we handle manifest receivers in a process that always
+ * responds with {@link DeadObjectException} even after restarting.
+ */
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_AVOID_REPEATED_BCAST_RE_ENQUEUES)
+ public void testRepeatedDead_Manifest() throws Exception {
+ final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+ mNewProcessBehaviors.put(PACKAGE_GREEN, ProcessBehavior.DEAD);
+
+ final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
+ withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
+ withPriority(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), 0))));
+ final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+ enqueueBroadcast(makeBroadcastRecord(timezone, callerApp,
+ List.of(makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW))));
+ waitForIdle();
+
+ final ProcessRecord receiverGreenApp = mAms.getProcessRecordLocked(PACKAGE_GREEN,
+ getUidForPackage(PACKAGE_GREEN));
+ // Modern queue always kills the target process when broadcast delivery fails, where as
+ // the legacy queue leaves the process killing task to AMS
+ if (mImpl == Impl.MODERN) {
+ assertNull(receiverGreenApp);
+ }
+ final ProcessRecord receiverBlueApp = mAms.getProcessRecordLocked(PACKAGE_BLUE,
+ getUidForPackage(PACKAGE_BLUE));
+ verifyScheduleReceiver(receiverBlueApp, airplane);
+ final ProcessRecord receiverYellowApp = mAms.getProcessRecordLocked(PACKAGE_YELLOW,
+ getUidForPackage(PACKAGE_YELLOW));
+ verifyScheduleReceiver(receiverYellowApp, timezone);
+ }
+
+ /**
* Verify that we handle the system failing to start a process.
*/
@Test
@@ -1142,6 +1193,49 @@
}
/**
+ * Verify that when BroadcastQueue doesn't get notified when a process gets killed repeatedly,
+ * it doesn't get stuck.
+ */
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_AVOID_REPEATED_BCAST_RE_ENQUEUES)
+ public void testRepeatedKillWithoutNotify() throws Exception {
+ // Legacy queue does not handle repeated kills that don't get notified.
+ Assume.assumeTrue(mImpl == Impl.MODERN);
+
+ final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+ final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
+
+ mNewProcessStartBehaviors.put(PACKAGE_GREEN, ProcessStartBehavior.KILLED_WITHOUT_NOTIFY);
+
+ final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
+ withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
+ withPriority(makeRegisteredReceiver(receiverBlueApp), 5),
+ withPriority(makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW), 0))));
+
+ final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+ enqueueBroadcast(makeBroadcastRecord(timezone, callerApp,
+ List.of(makeManifestReceiver(PACKAGE_ORANGE, CLASS_ORANGE))));
+
+ waitForIdle();
+ final ProcessRecord receiverGreenApp = mAms.getProcessRecordLocked(PACKAGE_GREEN,
+ getUidForPackage(PACKAGE_GREEN));
+ final ProcessRecord receiverYellowApp = mAms.getProcessRecordLocked(PACKAGE_YELLOW,
+ getUidForPackage(PACKAGE_YELLOW));
+ final ProcessRecord receiverOrangeApp = mAms.getProcessRecordLocked(PACKAGE_ORANGE,
+ getUidForPackage(PACKAGE_ORANGE));
+
+ // Modern queue always kills the target process when broadcast delivery fails, where as
+ // the legacy queue leaves the process killing task to AMS
+ if (mImpl == Impl.MODERN) {
+ assertNull(receiverGreenApp);
+ }
+ verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, airplane);
+ verifyScheduleReceiver(times(1), receiverYellowApp, airplane);
+ verifyScheduleReceiver(times(1), receiverOrangeApp, timezone);
+ }
+
+ /**
* Verify that a broadcast sent to a frozen app, which gets killed as part of unfreezing
* process due to pending sync binder transactions, is delivered as expected.
*/