Loading core/api/current.txt +1 −1 Original line number Diff line number Diff line Loading @@ -34768,7 +34768,7 @@ package android.os { method @FlaggedApi("android.os.message_queue_testability") public boolean isBlockedOnSyncBarrier(); method public android.os.Message next(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public Long peekWhen(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public android.os.Message pop(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public android.os.Message poll(); method public void recycle(android.os.Message); method public void release(); } core/api/system-current.txt +2 −2 Original line number Diff line number Diff line Loading @@ -12713,14 +12713,14 @@ package android.security.authenticationpolicy { } @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable { ctor public DisableSecureLockDeviceParams(@NonNull String); ctor public DisableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.DisableSecureLockDeviceParams> CREATOR; } @FlaggedApi("android.security.secure_lockdown") public final class EnableSecureLockDeviceParams implements android.os.Parcelable { ctor public EnableSecureLockDeviceParams(@NonNull String); ctor public EnableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.EnableSecureLockDeviceParams> CREATOR; core/java/android/app/BroadcastStickyCache.java +2 −1 Original line number Diff line number Diff line Loading @@ -214,7 +214,8 @@ public class BroadcastStickyCache { // We only need 1 entry per cache but just to be on the safer side we are choosing 32 // although we don't expect more than 1. sActionConfigMap.put(action, new Config(32, IpcDataCache.MODULE_SYSTEM, sActionApiNameMap.get(action))); new Config(32, IpcDataCache.MODULE_SYSTEM, sActionApiNameMap.get(action)).cacheNulls(true)); } return sActionConfigMap.get(action); Loading core/java/android/app/jank/JankTracker.java +15 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.ViewTreeObserver; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.HashMap; /** * This class is responsible for registering callbacks that will receive JankData batches. Loading Loading @@ -173,6 +174,15 @@ public class JankTracker { mStateTracker.retrieveAllStates(stateDataList); } /** * Retrieve all pending jank stats before they are logged, this is intended for testing * purposes only. */ @VisibleForTesting public HashMap<String, JankDataProcessor.PendingJankStat> getPendingJankStats() { return mJankDataProcessor.getPendingJankStats(); } /** * Only intended to be used by tests, the runnable that registers the listeners may not run * in time for tests to pass. This forces them to run immediately. Loading @@ -192,7 +202,11 @@ public class JankTracker { */ } private boolean shouldTrack() { /** * Returns whether jank tracking is enabled or not. */ @VisibleForTesting public boolean shouldTrack() { return mTrackingEnabled && mListenersRegistered; } Loading core/java/android/appwidget/AppWidgetManager.java +114 −1 Original line number Diff line number Diff line Loading @@ -37,36 +37,44 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.Intent.FilterComparison; import android.content.IntentSender; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import android.widget.RemoteViews; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FunctionalUtils; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Updates AppWidget state; gets information about installed AppWidget providers and other Loading Loading @@ -592,6 +600,8 @@ public class AppWidgetManager { private boolean mHasPostedLegacyLists = false; private @NonNull ServiceCollectionCache mServiceCollectionCache; /** * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context * Context} object. Loading @@ -612,6 +622,7 @@ public class AppWidgetManager { mPackageName = context.getOpPackageName(); mService = service; mDisplayMetrics = context.getResources().getDisplayMetrics(); mServiceCollectionCache = new ServiceCollectionCache(context, /* timeout= */ 5000L); if (mService == null) { return; } Loading Loading @@ -649,7 +660,7 @@ public class AppWidgetManager { final RemoteViews viewsCopy = new RemoteViews(original); Runnable updateWidgetWithTask = () -> { try { viewsCopy.collectAllIntents(mMaxBitmapMemory).get(); viewsCopy.collectAllIntents(mMaxBitmapMemory, mServiceCollectionCache).get(); action.acceptOrThrow(viewsCopy); } catch (Exception e) { Log.e(TAG, failureMsg, e); Loading Loading @@ -1629,4 +1640,106 @@ public class AppWidgetManager { thread.start(); return thread.getThreadHandler(); } /** * @hide */ public static class ServiceCollectionCache { private final Context mContext; private final Handler mHandler; private final long mTimeOut; private final Map<FilterComparison, ConnectionTask> mActiveConnections = new ArrayMap<>(); public ServiceCollectionCache(Context context, long timeOut) { mContext = context; mHandler = new Handler(BackgroundThread.getHandler().getLooper()); mTimeOut = timeOut; } /** * Connect to the service indicated by the {@code Intent}, and consume the binder on the * specified executor */ public void connectAndConsume(Intent intent, Consumer<IBinder> task, Executor executor) { mHandler.post(() -> connectAndConsumeInner(intent, task, executor)); } private void connectAndConsumeInner(Intent intent, Consumer<IBinder> task, Executor executor) { ConnectionTask activeConnection = mActiveConnections.computeIfAbsent( new FilterComparison(intent), ConnectionTask::new); activeConnection.add(task, executor); } private class ConnectionTask implements ServiceConnection { private final Runnable mDestroyAfterTimeout = this::onDestroyTimeout; private final ArrayDeque<Pair<Consumer<IBinder>, Executor>> mTaskQueue = new ArrayDeque<>(); private boolean mOnDestroyTimeout = false; private IBinder mIBinder; ConnectionTask(@NonNull FilterComparison filter) { mContext.bindService(filter.getIntent(), Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE), mHandler::post, this); } @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mIBinder = iBinder; mHandler.post(this::handleNext); } @Override public void onNullBinding(ComponentName name) { // Use an empty binder, follow up tasks will handle the failure onServiceConnected(name, new Binder()); } @Override public void onServiceDisconnected(ComponentName componentName) { } void add(Consumer<IBinder> task, Executor executor) { mTaskQueue.add(Pair.create(task, executor)); if (mOnDestroyTimeout) { // If we are waiting for timeout, cancel it and execute the next task handleNext(); } } private void handleNext() { mHandler.removeCallbacks(mDestroyAfterTimeout); Pair<Consumer<IBinder>, Executor> next = mTaskQueue.pollFirst(); if (next != null) { mOnDestroyTimeout = false; next.second.execute(() -> { next.first.accept(mIBinder); mHandler.post(this::handleNext); }); } else { // Finished all tasks, start a timeout to unbind this service mOnDestroyTimeout = true; mHandler.postDelayed(mDestroyAfterTimeout, mTimeOut); } } /** * Called after we have waited for {@link #mTimeOut} after the last task is finished */ private void onDestroyTimeout() { if (!mTaskQueue.isEmpty()) { handleNext(); return; } mContext.unbindService(this); mActiveConnections.values().remove(this); } } } } Loading
core/api/current.txt +1 −1 Original line number Diff line number Diff line Loading @@ -34768,7 +34768,7 @@ package android.os { method @FlaggedApi("android.os.message_queue_testability") public boolean isBlockedOnSyncBarrier(); method public android.os.Message next(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public Long peekWhen(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public android.os.Message pop(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public android.os.Message poll(); method public void recycle(android.os.Message); method public void release(); }
core/api/system-current.txt +2 −2 Original line number Diff line number Diff line Loading @@ -12713,14 +12713,14 @@ package android.security.authenticationpolicy { } @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable { ctor public DisableSecureLockDeviceParams(@NonNull String); ctor public DisableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.DisableSecureLockDeviceParams> CREATOR; } @FlaggedApi("android.security.secure_lockdown") public final class EnableSecureLockDeviceParams implements android.os.Parcelable { ctor public EnableSecureLockDeviceParams(@NonNull String); ctor public EnableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.EnableSecureLockDeviceParams> CREATOR;
core/java/android/app/BroadcastStickyCache.java +2 −1 Original line number Diff line number Diff line Loading @@ -214,7 +214,8 @@ public class BroadcastStickyCache { // We only need 1 entry per cache but just to be on the safer side we are choosing 32 // although we don't expect more than 1. sActionConfigMap.put(action, new Config(32, IpcDataCache.MODULE_SYSTEM, sActionApiNameMap.get(action))); new Config(32, IpcDataCache.MODULE_SYSTEM, sActionApiNameMap.get(action)).cacheNulls(true)); } return sActionConfigMap.get(action); Loading
core/java/android/app/jank/JankTracker.java +15 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.ViewTreeObserver; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.HashMap; /** * This class is responsible for registering callbacks that will receive JankData batches. Loading Loading @@ -173,6 +174,15 @@ public class JankTracker { mStateTracker.retrieveAllStates(stateDataList); } /** * Retrieve all pending jank stats before they are logged, this is intended for testing * purposes only. */ @VisibleForTesting public HashMap<String, JankDataProcessor.PendingJankStat> getPendingJankStats() { return mJankDataProcessor.getPendingJankStats(); } /** * Only intended to be used by tests, the runnable that registers the listeners may not run * in time for tests to pass. This forces them to run immediately. Loading @@ -192,7 +202,11 @@ public class JankTracker { */ } private boolean shouldTrack() { /** * Returns whether jank tracking is enabled or not. */ @VisibleForTesting public boolean shouldTrack() { return mTrackingEnabled && mListenersRegistered; } Loading
core/java/android/appwidget/AppWidgetManager.java +114 −1 Original line number Diff line number Diff line Loading @@ -37,36 +37,44 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.Intent.FilterComparison; import android.content.IntentSender; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import android.widget.RemoteViews; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FunctionalUtils; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Updates AppWidget state; gets information about installed AppWidget providers and other Loading Loading @@ -592,6 +600,8 @@ public class AppWidgetManager { private boolean mHasPostedLegacyLists = false; private @NonNull ServiceCollectionCache mServiceCollectionCache; /** * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context * Context} object. Loading @@ -612,6 +622,7 @@ public class AppWidgetManager { mPackageName = context.getOpPackageName(); mService = service; mDisplayMetrics = context.getResources().getDisplayMetrics(); mServiceCollectionCache = new ServiceCollectionCache(context, /* timeout= */ 5000L); if (mService == null) { return; } Loading Loading @@ -649,7 +660,7 @@ public class AppWidgetManager { final RemoteViews viewsCopy = new RemoteViews(original); Runnable updateWidgetWithTask = () -> { try { viewsCopy.collectAllIntents(mMaxBitmapMemory).get(); viewsCopy.collectAllIntents(mMaxBitmapMemory, mServiceCollectionCache).get(); action.acceptOrThrow(viewsCopy); } catch (Exception e) { Log.e(TAG, failureMsg, e); Loading Loading @@ -1629,4 +1640,106 @@ public class AppWidgetManager { thread.start(); return thread.getThreadHandler(); } /** * @hide */ public static class ServiceCollectionCache { private final Context mContext; private final Handler mHandler; private final long mTimeOut; private final Map<FilterComparison, ConnectionTask> mActiveConnections = new ArrayMap<>(); public ServiceCollectionCache(Context context, long timeOut) { mContext = context; mHandler = new Handler(BackgroundThread.getHandler().getLooper()); mTimeOut = timeOut; } /** * Connect to the service indicated by the {@code Intent}, and consume the binder on the * specified executor */ public void connectAndConsume(Intent intent, Consumer<IBinder> task, Executor executor) { mHandler.post(() -> connectAndConsumeInner(intent, task, executor)); } private void connectAndConsumeInner(Intent intent, Consumer<IBinder> task, Executor executor) { ConnectionTask activeConnection = mActiveConnections.computeIfAbsent( new FilterComparison(intent), ConnectionTask::new); activeConnection.add(task, executor); } private class ConnectionTask implements ServiceConnection { private final Runnable mDestroyAfterTimeout = this::onDestroyTimeout; private final ArrayDeque<Pair<Consumer<IBinder>, Executor>> mTaskQueue = new ArrayDeque<>(); private boolean mOnDestroyTimeout = false; private IBinder mIBinder; ConnectionTask(@NonNull FilterComparison filter) { mContext.bindService(filter.getIntent(), Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE), mHandler::post, this); } @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mIBinder = iBinder; mHandler.post(this::handleNext); } @Override public void onNullBinding(ComponentName name) { // Use an empty binder, follow up tasks will handle the failure onServiceConnected(name, new Binder()); } @Override public void onServiceDisconnected(ComponentName componentName) { } void add(Consumer<IBinder> task, Executor executor) { mTaskQueue.add(Pair.create(task, executor)); if (mOnDestroyTimeout) { // If we are waiting for timeout, cancel it and execute the next task handleNext(); } } private void handleNext() { mHandler.removeCallbacks(mDestroyAfterTimeout); Pair<Consumer<IBinder>, Executor> next = mTaskQueue.pollFirst(); if (next != null) { mOnDestroyTimeout = false; next.second.execute(() -> { next.first.accept(mIBinder); mHandler.post(this::handleNext); }); } else { // Finished all tasks, start a timeout to unbind this service mOnDestroyTimeout = true; mHandler.postDelayed(mDestroyAfterTimeout, mTimeOut); } } /** * Called after we have waited for {@link #mTimeOut} after the last task is finished */ private void onDestroyTimeout() { if (!mTaskQueue.isEmpty()) { handleNext(); return; } mContext.unbindService(this); mActiveConnections.values().remove(this); } } } }