diff options
21 files changed, 484 insertions, 98 deletions
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index a90eb88bc109..98a8cbd8a73c 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2356,10 +2356,11 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p>A subset of the available request keys that can be overridden for * physical devices backing a logical multi-camera.</p> * <p>This is a subset of android.request.availableRequestKeys which contains a list - * of keys that can be overridden using {@link CaptureRequest.Builder#setPhysicalCameraKey }. + * of keys that can be overridden using + * {@link android.hardware.camera2.CaptureRequest.Builder#setPhysicalCameraKey }. * The respective value of such request key can be obtained by calling - * {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain - * individual physical device requests must be built via + * {@link android.hardware.camera2.CaptureRequest.Builder#getPhysicalCameraKey }. + * Capture requests that contain individual physical device requests must be built via * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * <p><b>Limited capability</b> - @@ -2759,7 +2760,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </table> * <p>For applications targeting SDK version 31 or newer, if the mobile device declares to be * media performance class 12 or higher by setting - * {@link android.os.Build.VERSION_CODES.MEDIA_PERFORMANCE_CLASS } to be 31 or larger, + * {@link android.os.Build.VERSION#MEDIA_PERFORMANCE_CLASS } to be 31 or larger, * the primary camera devices (first rear/front camera in the camera ID list) will not * support JPEG sizes smaller than 1080p. If the application configures a JPEG stream * smaller than 1080p, the camera device will round up the JPEG image size to at least @@ -2833,7 +2834,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </table> * <p>For applications targeting SDK version 31 or newer, if the mobile device doesn't declare * to be media performance class 12 or better by setting - * {@link android.os.Build.VERSION_CODES.MEDIA_PERFORMANCE_CLASS } to be 31 or larger, + * {@link android.os.Build.VERSION#MEDIA_PERFORMANCE_CLASS } to be 31 or larger, * or if the camera device isn't a primary rear/front camera, the minimum required output * stream configurations are the same as for applications targeting SDK version older than * 31.</p> @@ -2958,9 +2959,27 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * can provide.</p> * <p>Please reference the documentation for the image data destination to * check if it limits the maximum size for image data.</p> - * <p>The following table describes the minimum required output stream - * configurations based on the hardware level - * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p> + * <p>For applications targeting SDK version older than 31, the following table + * describes the minimum required output stream configurations based on the + * hardware level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}): + * Format | Size | Hardware Level | Notes + * :-------------------------------------------------:|:--------------------------------------------:|:--------------:|:--------------: + * {@link android.graphics.ImageFormat#JPEG } | {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} (*1) | Any | + * {@link android.graphics.ImageFormat#JPEG } | 1920x1080 (1080p) | Any | if 1080p <= activeArraySize + * {@link android.graphics.ImageFormat#JPEG } | 1280x720 (720p) | Any | if 720p <= activeArraySize + * {@link android.graphics.ImageFormat#JPEG } | 640x480 (480p) | Any | if 480p <= activeArraySize + * {@link android.graphics.ImageFormat#JPEG } | 320x240 (240p) | Any | if 240p <= activeArraySize + * {@link android.graphics.ImageFormat#YUV_420_888 } | all output sizes available for JPEG | FULL | + * {@link android.graphics.ImageFormat#YUV_420_888 } | all output sizes available for JPEG, up to the maximum video size | LIMITED | + * {@link android.graphics.ImageFormat#PRIVATE } | same as YUV_420_888 | Any |</p> + * <p>For applications targeting SDK version 31 or newer, if the mobile device declares to be + * media performance class 12 or higher by setting + * {@link android.os.Build.VERSION#MEDIA_PERFORMANCE_CLASS } to be 31 or larger, + * the primary camera devices (first rear/front camera in the camera ID list) will not + * support JPEG sizes smaller than 1080p. If the application configures a JPEG stream + * smaller than 1080p, the camera device will round up the JPEG image size to at least + * 1080p. The requirements for IMPLEMENTATION_DEFINED and YUV_420_888 stay the same. + * This new minimum required output stream configurations are illustrated by the table below:</p> * <table> * <thead> * <tr> @@ -2984,32 +3003,38 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <td align="center">if 1080p <= activeArraySize</td> * </tr> * <tr> - * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td> - * <td align="center">1280x720 (720p)</td> - * <td align="center">Any</td> + * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td> + * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td> + * <td align="center">FULL</td> + * <td align="center"></td> + * </tr> + * <tr> + * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td> + * <td align="center">1920x1080 (1080p)</td> + * <td align="center">FULL</td> + * <td align="center">if 1080p <= activeArraySize</td> + * </tr> + * <tr> + * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td> + * <td align="center">1280x720 (720)</td> + * <td align="center">FULL</td> * <td align="center">if 720p <= activeArraySize</td> * </tr> * <tr> - * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td> + * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td> * <td align="center">640x480 (480p)</td> - * <td align="center">Any</td> + * <td align="center">FULL</td> * <td align="center">if 480p <= activeArraySize</td> * </tr> * <tr> - * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td> - * <td align="center">320x240 (240p)</td> - * <td align="center">Any</td> - * <td align="center">if 240p <= activeArraySize</td> - * </tr> - * <tr> * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td> - * <td align="center">all output sizes available for JPEG</td> + * <td align="center">320x240 (240p)</td> * <td align="center">FULL</td> - * <td align="center"></td> + * <td align="center">if 240p <= activeArraySize</td> * </tr> * <tr> * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td> - * <td align="center">all output sizes available for JPEG, up to the maximum video size</td> + * <td align="center">all output sizes available for FULL hardware level, up to the maximum video size</td> * <td align="center">LIMITED</td> * <td align="center"></td> * </tr> @@ -3021,6 +3046,12 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </tr> * </tbody> * </table> + * <p>For applications targeting SDK version 31 or newer, if the mobile device doesn't declare + * to be media performance class 12 or better by setting + * {@link android.os.Build.VERSION#MEDIA_PERFORMANCE_CLASS } to be 31 or larger, + * or if the camera device isn't a primary rear/front camera, the minimum required output + * stream configurations are the same as for applications targeting SDK version older than + * 31.</p> * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} and {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional mandatory * stream configurations on a per-capability basis.</p> * <p>*1: For JPEG format, the sizes may be restricted by below conditions:</p> diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java index cf611fb3adcf..0f6010fffcb6 100644 --- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java @@ -854,7 +854,7 @@ public final class CameraExtensionCharacteristics { Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>) crKey; ret.addAll(requestChars.getAvailableKeyList(CaptureRequest.class, crKeyTyped, - requestKeys, /*includeSynthetic*/ false)); + requestKeys, /*includeSynthetic*/ true)); } // Jpeg quality and orientation must always be supported @@ -929,7 +929,7 @@ public final class CameraExtensionCharacteristics { Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>)crKey; ret.addAll(resultChars.getAvailableKeyList(CaptureResult.class, crKeyTyped, - resultKeys, /*includeSynthetic*/ false)); + resultKeys, /*includeSynthetic*/ true)); // Jpeg quality, orientation and sensor timestamp must always be supported if (!ret.contains(CaptureResult.JPEG_QUALITY)) { diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index e5dab0539a8e..0418a4bb9f80 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -31,6 +31,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import java.io.Serializable; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Set; import java.util.function.BiFunction; @@ -102,7 +103,7 @@ public class BaseBundle { /* * If mParcelledData is non-null, then mMap will be null and the * data are stored as a Parcel containing a Bundle. When the data - * are unparcelled, mParcelledData willbe set to null. + * are unparcelled, mParcelledData will be set to null. */ @UnsupportedAppUsage volatile Parcel mParcelledData = null; @@ -112,6 +113,19 @@ public class BaseBundle { */ private boolean mParcelledByNative; + /* + * Flag indicating if mParcelledData is only referenced in this bundle. + * mParcelledData could be referenced by other bundles if mMap contains lazy values, + * and bundle data is copied to another bundle using putAll or the copy constructors. + */ + boolean mOwnsLazyValues = true; + + /* + * As mParcelledData is set to null when it is unparcelled, we keep a weak reference to + * it to aid in recycling it. Do not use this reference otherwise. + */ + private WeakReference<Parcel> mWeakParcelledData = null; + /** * The ClassLoader used when unparcelling data from mParcelledData. */ @@ -200,6 +214,9 @@ public class BaseBundle { mClassLoader = from.mClassLoader; if (from.mMap != null) { + mOwnsLazyValues = false; + from.mOwnsLazyValues = false; + if (!deep) { mMap = new ArrayMap<>(from.mMap); } else { @@ -434,6 +451,9 @@ public class BaseBundle { mMap = map; if (recycleParcel) { recycleParcel(parcelledData); + mWeakParcelledData = null; + } else { + mWeakParcelledData = new WeakReference<>(parcelledData); } mParcelledByNative = false; mParcelledData = null; @@ -575,6 +595,10 @@ public class BaseBundle { */ public void clear() { unparcel(); + if (mOwnsLazyValues && mWeakParcelledData != null) { + recycleParcel(mWeakParcelledData.get()); + mWeakParcelledData = null; + } mMap.clear(); } diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index cf28c1639fac..7e355d95cdb3 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -301,6 +301,8 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { public void putAll(Bundle bundle) { unparcel(); bundle.unparcel(); + mOwnsLazyValues = false; + bundle.mOwnsLazyValues = false; mMap.putAll(bundle.mMap); // FD state is now known if and only if both bundles already knew diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 7e264cea46bb..536a0ac6403b 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -41,11 +41,13 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.SystemClock; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceControl.Transaction; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; +import android.window.SurfaceSyncer; import com.android.internal.view.SurfaceCallbackHelper; @@ -204,6 +206,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private int mSurfaceFlags = SurfaceControl.HIDDEN; + private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer(); + private final ArraySet<Integer> mSyncIds = new ArraySet<>(); + /** * Transaction that should be used from the render thread. This transaction is only thread safe * with other calls directly from the render thread. @@ -1018,7 +1023,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (shouldSyncBuffer) { handleSyncBufferCallback(callbacks, syncBufferTransactionCallback); } else { - redrawNeededAsync(callbacks, this::onDrawFinished); + handleSyncNoBuffer(callbacks); } } } @@ -1061,7 +1066,23 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall syncBufferCallback.onBufferReady(t); onDrawFinished(); })); + } + + private void handleSyncNoBuffer(SurfaceHolder.Callback[] callbacks) { + final int syncId = mSurfaceSyncer.setupSync(this::onDrawFinished); + mSurfaceSyncer.addToSync(syncId, syncBufferCallback -> redrawNeededAsync(callbacks, + () -> { + syncBufferCallback.onBufferReady(null); + synchronized (mSyncIds) { + mSyncIds.remove(syncId); + } + })); + + mSurfaceSyncer.markSyncReady(syncId); + synchronized (mSyncIds) { + mSyncIds.add(syncId); + } } private void redrawNeededAsync(SurfaceHolder.Callback[] callbacks, @@ -1070,6 +1091,21 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); } + /** + * @hide + */ + @Override + public void surfaceSyncStarted() { + ViewRootImpl viewRoot = getViewRootImpl(); + if (viewRoot != null) { + synchronized (mSyncIds) { + for (int syncId : mSyncIds) { + viewRoot.mergeSync(syncId, mSurfaceSyncer); + } + } + } + } + private static class SyncBufferTransactionCallback { private final CountDownLatch mCountDownLatch = new CountDownLatch(1); private Transaction mTransaction; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index ad3379f4c46e..f163530f997b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2048,6 +2048,7 @@ public final class ViewRootImpl implements ViewParent, void surfaceCreated(Transaction t); void surfaceReplaced(Transaction t); void surfaceDestroyed(); + default void surfaceSyncStarted() {}; } private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>(); @@ -2082,6 +2083,12 @@ public final class ViewRootImpl implements ViewParent, } } + private void notifySurfaceSyncStarted() { + for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { + mSurfaceChangedCallbacks.get(i).surfaceSyncStarted(); + } + } + /** * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the * surface insets. If the layer does not exist, it is created. @@ -3541,6 +3548,7 @@ public final class ViewRootImpl implements ViewParent, Log.d(mTag, "Setup new sync id=" + mSyncId); } mSurfaceSyncer.addToSync(mSyncId, mSyncTarget); + notifySurfaceSyncStarted(); } private void notifyContentCatpureEvents() { @@ -10965,4 +10973,11 @@ public final class ViewRootImpl implements ViewParent, scheduleTraversals(); } } + + void mergeSync(int syncId, SurfaceSyncer otherSyncer) { + if (!isInLocalSync()) { + return; + } + mSurfaceSyncer.merge(mSyncId, syncId, otherSyncer); + } } diff --git a/core/java/android/window/SurfaceSyncer.java b/core/java/android/window/SurfaceSyncer.java index 0e011bb0d0b3..e6eb07162a3b 100644 --- a/core/java/android/window/SurfaceSyncer.java +++ b/core/java/android/window/SurfaceSyncer.java @@ -117,13 +117,18 @@ public class SurfaceSyncer { */ public int setupSync(@NonNull Consumer<Transaction> syncRequestComplete) { synchronized (mSyncSetLock) { - mIdCounter++; + final int syncId = mIdCounter++; if (DEBUG) { - Log.d(TAG, "setupSync " + mIdCounter); + Log.d(TAG, "setupSync " + syncId); } - SyncSet syncSet = new SyncSet(mIdCounter, syncRequestComplete); - mSyncSets.put(mIdCounter, syncSet); - return mIdCounter; + SyncSet syncSet = new SyncSet(syncId, transaction -> { + synchronized (mSyncSetLock) { + mSyncSets.remove(syncId); + } + syncRequestComplete.accept(transaction); + }); + mSyncSets.put(syncId, syncSet); + return syncId; } } @@ -138,7 +143,6 @@ public class SurfaceSyncer { SyncSet syncSet; synchronized (mSyncSetLock) { syncSet = mSyncSets.get(syncId); - mSyncSets.remove(syncId); } if (syncSet == null) { Log.e(TAG, "Failed to find syncSet for syncId=" + syncId); @@ -148,6 +152,31 @@ public class SurfaceSyncer { } /** + * Merge another SyncSet into the specified syncId. + * @param syncId The current syncId to merge into + * @param otherSyncId The other syncId to be merged + * @param otherSurfaceSyncer The other SurfaceSyncer where the otherSyncId is from + */ + public void merge(int syncId, int otherSyncId, SurfaceSyncer otherSurfaceSyncer) { + SyncSet syncSet; + synchronized (mSyncSetLock) { + syncSet = mSyncSets.get(syncId); + } + + SyncSet otherSyncSet = otherSurfaceSyncer.getAndValidateSyncSet(otherSyncId); + if (otherSyncSet == null) { + return; + } + + if (DEBUG) { + Log.d(TAG, + "merge id=" + otherSyncId + " from=" + otherSurfaceSyncer + " into id=" + syncId + + " from" + this); + } + syncSet.merge(otherSyncSet); + } + + /** * Add a SurfaceView to a sync set. This is different than {@link #addToSync(int, View)} because * it requires the caller to notify the start and finish drawing in order to sync. * @@ -199,8 +228,7 @@ public class SurfaceSyncer { if (DEBUG) { Log.d(TAG, "addToSync id=" + syncId); } - syncSet.addSyncableSurface(syncTarget); - return true; + return syncSet.addSyncableSurface(syncTarget); } /** @@ -284,14 +312,21 @@ public class SurfaceSyncer { private final Set<SyncTarget> mSyncTargets = new ArraySet<>(); private final int mSyncId; - private final Consumer<Transaction> mSyncRequestCompleteCallback; + @GuardedBy("mLock") + private Consumer<Transaction> mSyncRequestCompleteCallback; + + @GuardedBy("mLock") + private final Set<SyncSet> mMergedSyncSets = new ArraySet<>(); + + @GuardedBy("mLock") + private boolean mFinished; private SyncSet(int syncId, Consumer<Transaction> syncRequestComplete) { mSyncId = syncId; mSyncRequestCompleteCallback = syncRequestComplete; } - void addSyncableSurface(SyncTarget syncTarget) { + boolean addSyncableSurface(SyncTarget syncTarget) { SyncBufferCallback syncBufferCallback = new SyncBufferCallback() { @Override public void onBufferReady(Transaction t) { @@ -306,10 +341,16 @@ public class SurfaceSyncer { }; synchronized (mLock) { + if (mSyncReady) { + Log.e(TAG, "Sync " + mSyncId + " was already marked as ready. No more " + + "SyncTargets can be added."); + return false; + } mPendingSyncs.add(syncBufferCallback.hashCode()); mSyncTargets.add(syncTarget); } syncTarget.onReadyToSync(syncBufferCallback); + return true; } void markSyncReady() { @@ -321,10 +362,11 @@ public class SurfaceSyncer { @GuardedBy("mLock") private void checkIfSyncIsComplete() { - if (!mSyncReady || !mPendingSyncs.isEmpty()) { + if (!mSyncReady || !mPendingSyncs.isEmpty() || !mMergedSyncSets.isEmpty()) { if (DEBUG) { Log.d(TAG, "Syncable is not complete. mSyncReady=" + mSyncReady - + " mPendingSyncs=" + mPendingSyncs.size()); + + " mPendingSyncs=" + mPendingSyncs.size() + " mergedSyncs=" + + mMergedSyncSets.size()); } return; } @@ -338,6 +380,7 @@ public class SurfaceSyncer { } mSyncTargets.clear(); mSyncRequestCompleteCallback.accept(mTransaction); + mFinished = true; } /** @@ -349,6 +392,50 @@ public class SurfaceSyncer { mTransaction.merge(t); } } + + public void updateCallback(Consumer<Transaction> transactionConsumer) { + synchronized (mLock) { + if (mFinished) { + Log.e(TAG, "Attempting to merge SyncSet " + mSyncId + " when sync is" + + " already complete"); + transactionConsumer.accept(new Transaction()); + } + + final Consumer<Transaction> oldCallback = mSyncRequestCompleteCallback; + mSyncRequestCompleteCallback = transaction -> { + oldCallback.accept(new Transaction()); + transactionConsumer.accept(transaction); + }; + } + } + + /** + * Merge a SyncSet into this SyncSet. Since SyncSets could still have pending SyncTargets, + * we need to make sure those can still complete before the mergeTo syncSet is considered + * complete. + * + * We keep track of all the merged SyncSets until they are marked as done, and then they + * are removed from the set. This SyncSet is not considered done until all the merged + * SyncSets are done. + * + * When the merged SyncSet is complete, it will invoke the original syncRequestComplete + * callback but send an empty transaction to ensure the changes are applied early. This + * is needed in case the original sync is relying on the callback to continue processing. + * + * @param otherSyncSet The other SyncSet to merge into this one. + */ + public void merge(SyncSet otherSyncSet) { + synchronized (mLock) { + mMergedSyncSets.add(otherSyncSet); + } + otherSyncSet.updateCallback(transaction -> { + synchronized (mLock) { + mMergedSyncSets.remove(otherSyncSet); + mTransaction.merge(transaction); + checkIfSyncIsComplete(); + } + }); + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java index b9ddd3650b86..0f9260c9deaa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java @@ -54,7 +54,13 @@ public interface TaskStackListenerCallback { default void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { } - default void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { } + /** + * @return whether the snapshot is consumed and the lifecycle of the snapshot extends beyond + * the lifecycle of this callback. + */ + default boolean onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { + return false; + } default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java index 85e2654e4ebe..9e0a48b13413 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java @@ -275,9 +275,15 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. } case ON_TASK_SNAPSHOT_CHANGED: { Trace.beginSection("onTaskSnapshotChanged"); + final TaskSnapshot snapshot = (TaskSnapshot) msg.obj; + boolean snapshotConsumed = false; for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { - mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1, - (TaskSnapshot) msg.obj); + boolean consumed = mTaskStackListeners.get(i).onTaskSnapshotChanged( + msg.arg1, snapshot); + snapshotConsumed |= consumed; + } + if (!snapshotConsumed && snapshot.getHardwareBuffer() != null) { + snapshot.getHardwareBuffer().close(); } Trace.endSection(); break; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 7ea32a6d8f86..41e23647a6a4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -76,6 +76,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.Slog; +import android.view.Choreographer; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; @@ -1124,6 +1125,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDividerFadeInAnimator.cancel(); return; } + transaction.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); transaction.setAlpha(dividerLeash, (float) animation.getAnimatedValue()); transaction.apply(); }); @@ -1216,17 +1218,23 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onLayoutPositionChanging(SplitLayout layout) { - mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t, false /* applyResizingOffset */)); + final SurfaceControl.Transaction t = mTransactionPool.acquire(); + t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); + updateSurfaceBounds(layout, t, false /* applyResizingOffset */); + t.apply(); + mTransactionPool.release(t); } @Override public void onLayoutSizeChanging(SplitLayout layout) { - mSyncQueue.runInSync(t -> { - setResizingSplits(true /* resizing */); - updateSurfaceBounds(layout, t, true /* applyResizingOffset */); - mMainStage.onResizing(getMainStageBounds(), t); - mSideStage.onResizing(getSideStageBounds(), t); - }); + final SurfaceControl.Transaction t = mTransactionPool.acquire(); + t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); + setResizingSplits(true /* resizing */); + updateSurfaceBounds(layout, t, true /* applyResizingOffset */); + mMainStage.onResizing(getMainStageBounds(), t); + mSideStage.onResizing(getSideStageBounds(), t); + t.apply(); + mTransactionPool.release(t); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index cde4247c575f..95bc579a4a51 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -389,6 +389,9 @@ public class TaskSnapshotWindow { reportDrawn(); // In case window manager leaks us, make sure we don't retain the snapshot. + if (mSnapshot.getHardwareBuffer() != null) { + mSnapshot.getHardwareBuffer().close(); + } mSnapshot = null; mSurfaceControl.release(); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java index 1142e05f4649..07733473f298 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java @@ -65,6 +65,12 @@ public class ThumbnailData { snapshotId = 0; } + public void recycleBitmap() { + if (thumbnail != null) { + thumbnail.recycle(); + } + } + private static Bitmap makeThumbnail(TaskSnapshot snapshot) { Bitmap thumbnail = null; try (final HardwareBuffer buffer = snapshot.getHardwareBuffer()) { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java index acd42228f4e2..362d7a9390d4 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java @@ -33,7 +33,14 @@ public interface TaskStackChangeListener { // Main thread callbacks default void onTaskStackChanged() { } - default void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { } + + /** + * @return whether the snapshot is consumed and the lifecycle of the snapshot extends beyond + * the lifecycle of this callback. + */ + default boolean onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { + return false; + } default void onActivityPinned(String packageName, int userId, int taskId, int stackId) { } default void onActivityUnpinned() { } default void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java index 2fd5aaefa34b..8af934f66b2a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java @@ -294,8 +294,17 @@ public class TaskStackChangeListeners { Trace.beginSection("onTaskSnapshotChanged"); final TaskSnapshot snapshot = (TaskSnapshot) msg.obj; final ThumbnailData thumbnail = new ThumbnailData(snapshot); + boolean snapshotConsumed = false; for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { - mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1, thumbnail); + boolean consumed = mTaskStackListeners.get(i).onTaskSnapshotChanged( + msg.arg1, thumbnail); + snapshotConsumed |= consumed; + } + if (!snapshotConsumed) { + thumbnail.recycleBitmap(); + if (snapshot.getHardwareBuffer() != null) { + snapshot.getHardwareBuffer().close(); + } } Trace.endSection(); break; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 233f3648aeb3..6da2f50aac27 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -406,6 +406,15 @@ public class AuthContainerView extends LinearLayout } @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + if (!hasWindowFocus) { + Log.v(TAG, "Lost window focus, dismissing the dialog"); + animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); + } + } + + @Override public void onAttachedToWindow() { super.onAttachedToWindow(); @@ -720,7 +729,7 @@ public class AuthContainerView extends LinearLayout final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL, + WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL, windowFlags, PixelFormat.TRANSLUCENT); lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index 2341928b2565..52b5857a2106 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -106,6 +106,23 @@ class AuthContainerViewTest : SysuiTestCase() { } @Test + fun testDismissesOnFocusLoss() { + val container = initializeContainer() + waitForIdleSync() + + verify(callback).onDialogAnimatedIn() + + container.onWindowFocusChanged(false) + waitForIdleSync() + + verify(callback).onDismissed( + eq(AuthDialogCallback.DISMISSED_USER_CANCELED), + eq<ByteArray?>(null) /* credentialAttestation */ + ) + assertThat(container.parent).isNull() + } + + @Test fun testActionAuthenticated_sendsDismissedAuthenticated() { val container = initializeContainer() container.mBiometricCallback.onAction( diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java index c6e595b1d785..01cee33fd81a 100644 --- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java +++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java @@ -174,7 +174,7 @@ public final class PresentationStatsEventLogger { public void logAndEndEvent() { if (!mEventInternal.isPresent()) { - Slog.wtf(null, "Shouldn't be logging AutofillPresentationEventReported again for same " + Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same " + "event"); return; } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index a4eaef98235d..8368b4dfe070 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -63,6 +63,12 @@ import static android.os.Process.SYSTEM_UID; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_BG_LAUNCH; +import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED; +import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD; +import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_HOT; +import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM; +import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__BIND; +import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__START; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; @@ -522,8 +528,9 @@ public final class ActiveServices { + " delayedStop=" + r.delayedStop); } else { try { - startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, - true); + final ServiceRecord.StartItem si = r.pendingStarts.get(0); + startServiceInnerLocked(this, si.intent, r, false, true, si.callingId, + r.startRequested); } catch (TransactionTooLargeException e) { // Ignore, nobody upstack cares. } @@ -865,6 +872,7 @@ public final class ActiveServices { if (unscheduleServiceRestartLocked(r, callingUid, false)) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r); } + final boolean wasStartRequested = r.startRequested; r.lastActivity = SystemClock.uptimeMillis(); r.startRequested = true; r.delayedStop = false; @@ -954,7 +962,8 @@ public final class ActiveServices { if (allowBackgroundActivityStarts) { r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken); } - ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); + ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting, + callingUid, wasStartRequested); return cmp; } @@ -1150,7 +1159,8 @@ public final class ActiveServices { } ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, - boolean callerFg, boolean addToStarting) throws TransactionTooLargeException { + boolean callerFg, boolean addToStarting, int callingUid, boolean wasStartRequested) + throws TransactionTooLargeException { synchronized (mAm.mProcessStats.mLock) { final ServiceState stracker = r.getTracker(); if (stracker != null) { @@ -1177,6 +1187,15 @@ public final class ActiveServices { return new ComponentName("!!", error); } + FrameworkStatsLog.write(SERVICE_REQUEST_EVENT_REPORTED, uid, callingUid, + ActivityManagerService.getShortAction(service.getAction()), + SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__START, false, + r.app == null || r.app.getThread() == null + ? SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD + : (wasStartRequested || !r.getConnections().isEmpty() + ? SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_HOT + : SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM)); + if (r.startRequested && addToStarting) { boolean first = smap.mStartingBackground.size() == 0; smap.mStartingBackground.add(r); @@ -2876,6 +2895,8 @@ public final class ActiveServices { mAm.requireAllowedAssociationsLocked(s.appInfo.packageName); } + final boolean wasStartRequested = s.startRequested; + final boolean hadConnections = !s.getConnections().isEmpty(); mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.mState.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode, s.instanceName, s.processName); @@ -2962,6 +2983,15 @@ public final class ActiveServices { mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE); } + FrameworkStatsLog.write(SERVICE_REQUEST_EVENT_REPORTED, s.appInfo.uid, callingUid, + ActivityManagerService.getShortAction(service.getAction()), + SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__BIND, false, + s.app == null || s.app.getThread() == null + ? SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD + : (wasStartRequested || hadConnections + ? SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_HOT + : SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM)); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b + ": received=" + b.intent.received + " apps=" + b.intent.apps.size() @@ -6917,7 +6947,8 @@ public final class ActiveServices { durationMs, r.mStartForegroundCount, ActivityManagerUtils.hashComponentNameForAtom(r.shortInstanceName), - r.mFgsHasNotificationPermission); + r.mFgsHasNotificationPermission, + r.foregroundServiceType); int event = 0; if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 71a28487a763..a78c64b6538d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5003,15 +5003,7 @@ public class ActivityManagerService extends IActivityManager.Stub final HostingRecord hostingRecord = app.getHostingRecord(); - final String action = hostingRecord.getAction(); - String shortAction = action; - if (action != null) { - // only log the last part of the action string to save stats data. - int index = action.lastIndexOf("."); - if (index != -1 && index != action.length() - 1) { - shortAction = action.substring(index + 1); - } - } + String shortAction = getShortAction(hostingRecord.getAction()); FrameworkStatsLog.write( FrameworkStatsLog.PROCESS_START_TIME, app.info.uid, @@ -5042,6 +5034,20 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** + * @return The last part of the string of an intent's action. + */ + static @Nullable String getShortAction(@Nullable String action) { + String shortAction = action; + if (action != null) { + int index = action.lastIndexOf('.'); + if (index != -1 && index != action.length() - 1) { + shortAction = action.substring(index + 1); + } + } + return shortAction; + } + void checkTime(long startTime, String where) { long now = SystemClock.uptimeMillis(); if ((now - startTime) > 50) { @@ -14262,7 +14268,7 @@ public class ActivityManagerService extends IActivityManager.Stub oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo, oldRecord.intent, Activity.RESULT_CANCELED, null, null, - false, false, oldRecord.userId); + false, false, oldRecord.userId, oldRecord.callingUid, callingUid); } catch (RemoteException e) { Slog.w(TAG, "Failure [" + queue.mQueueName + "] sending broadcast result of " diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index f7aa7c155719..43d0de9855fe 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -24,6 +24,11 @@ import static android.text.TextUtils.formatSimple; import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED; import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__BOOT_COMPLETED; import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__LOCKED_BOOT_COMPLETED; +import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED; +import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD; +import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM; +import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST; +import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT; @@ -316,7 +321,7 @@ public final class BroadcastQueue { } private final void processCurBroadcastLocked(BroadcastRecord r, - ProcessRecord app) throws RemoteException { + ProcessRecord app, int receiverType, int processTemperature) throws RemoteException { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " for app " + app); final IApplicationThread thread = app.getThread(); @@ -362,6 +367,10 @@ public final class BroadcastQueue { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; + FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, app.uid, + r.callingUid == -1 ? Process.SYSTEM_UID : r.callingUid, + ActivityManagerService.getShortAction(r.intent.getAction()), + receiverType, processTemperature); } finally { if (!started) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, @@ -398,7 +407,9 @@ public final class BroadcastQueue { } try { mPendingBroadcast = null; - processCurBroadcastLocked(br, app); + processCurBroadcastLocked(br, app, + BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST, + BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD); didSomething = true; } catch (Exception e) { Slog.w(TAG, "Exception in new application when starting receiver " @@ -628,8 +639,8 @@ public final class BroadcastQueue { void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, - boolean ordered, boolean sticky, int sendingUser) - throws RemoteException { + boolean ordered, boolean sticky, int sendingUser, + int receiverUid, int callingUid) throws RemoteException { // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null) { final IApplicationThread thread = app.getThread(); @@ -663,6 +674,12 @@ public final class BroadcastQueue { receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } + FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, + receiverUid == -1 ? Process.SYSTEM_UID : receiverUid, + callingUid == -1 ? Process.SYSTEM_UID : callingUid, + ActivityManagerService.getShortAction(intent.getAction()), + BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME, + BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM); } private void deliverToRegisteredReceiverLocked(BroadcastRecord r, @@ -965,7 +982,8 @@ public final class BroadcastQueue { maybeReportBroadcastDispatchedEventLocked(r, filter.owningUid); performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, - r.resultExtras, r.ordered, r.initialSticky, r.userId); + r.resultExtras, r.ordered, r.initialSticky, r.userId, + filter.receiverList.uid, r.callingUid); // parallel broadcasts are fire-and-forget, not bookended by a call to // finishReceiverLocked(), so we manage their activity-start token here if (filter.receiverList.app != null @@ -1317,7 +1335,8 @@ public final class BroadcastQueue { } performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, false, false, r.userId); + r.resultData, r.resultExtras, false, false, r.userId, + r.callingUid, r.callingUid); logBootCompletedBroadcastCompletionLatencyIfPossible(r); // Set this to null so that the reference // (local and remote) isn't kept in the mBroadcastHistory. @@ -1837,7 +1856,9 @@ public final class BroadcastQueue { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats); maybeAddAllowBackgroundActivityStartsToken(app, r); - processCurBroadcastLocked(r, app); + processCurBroadcastLocked(r, app, + BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST, + BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM); return; } catch (RemoteException e) { Slog.w(TAG, "Exception when sending broadcast to " diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerTest.java index cc28ea6f55d2..87382952314b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerTest.java @@ -48,11 +48,11 @@ public class SurfaceSyncerTest { public void testSyncOne() throws InterruptedException { final CountDownLatch finishedLatch = new CountDownLatch(1); int startSyncId = mSurfaceSyncer.setupSync(transaction -> finishedLatch.countDown()); - Syncable syncable = new Syncable(); - mSurfaceSyncer.addToSync(startSyncId, syncable); + SyncTarget syncTarget = new SyncTarget(); + mSurfaceSyncer.addToSync(startSyncId, syncTarget); mSurfaceSyncer.markSyncReady(startSyncId); - syncable.onBufferReady(); + syncTarget.onBufferReady(); finishedLatch.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch.getCount()); @@ -62,22 +62,22 @@ public class SurfaceSyncerTest { public void testSyncMultiple() throws InterruptedException { final CountDownLatch finishedLatch = new CountDownLatch(1); int startSyncId = mSurfaceSyncer.setupSync(transaction -> finishedLatch.countDown()); - Syncable syncable1 = new Syncable(); - Syncable syncable2 = new Syncable(); - Syncable syncable3 = new Syncable(); + SyncTarget syncTarget1 = new SyncTarget(); + SyncTarget syncTarget2 = new SyncTarget(); + SyncTarget syncTarget3 = new SyncTarget(); - mSurfaceSyncer.addToSync(startSyncId, syncable1); - mSurfaceSyncer.addToSync(startSyncId, syncable2); - mSurfaceSyncer.addToSync(startSyncId, syncable3); + mSurfaceSyncer.addToSync(startSyncId, syncTarget1); + mSurfaceSyncer.addToSync(startSyncId, syncTarget2); + mSurfaceSyncer.addToSync(startSyncId, syncTarget3); mSurfaceSyncer.markSyncReady(startSyncId); - syncable1.onBufferReady(); + syncTarget1.onBufferReady(); assertNotEquals(0, finishedLatch.getCount()); - syncable3.onBufferReady(); + syncTarget3.onBufferReady(); assertNotEquals(0, finishedLatch.getCount()); - syncable2.onBufferReady(); + syncTarget2.onBufferReady(); finishedLatch.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch.getCount()); @@ -85,7 +85,7 @@ public class SurfaceSyncerTest { @Test public void testInvalidSyncId() { - assertFalse(mSurfaceSyncer.addToSync(0, new Syncable())); + assertFalse(mSurfaceSyncer.addToSync(0, new SyncTarget())); } @Test @@ -93,14 +93,14 @@ public class SurfaceSyncerTest { final CountDownLatch finishedLatch = new CountDownLatch(1); int startSyncId = mSurfaceSyncer.setupSync(transaction -> finishedLatch.countDown()); - Syncable syncable1 = new Syncable(); - Syncable syncable2 = new Syncable(); + SyncTarget syncTarget1 = new SyncTarget(); + SyncTarget syncTarget2 = new SyncTarget(); - assertTrue(mSurfaceSyncer.addToSync(startSyncId, syncable1)); + assertTrue(mSurfaceSyncer.addToSync(startSyncId, syncTarget1)); mSurfaceSyncer.markSyncReady(startSyncId); // Adding to a sync that has been completed is also invalid since the sync id has been // cleared. - assertFalse(mSurfaceSyncer.addToSync(startSyncId, syncable2)); + assertFalse(mSurfaceSyncer.addToSync(startSyncId, syncTarget2)); } @Test @@ -110,27 +110,89 @@ public class SurfaceSyncerTest { int startSyncId1 = mSurfaceSyncer.setupSync(transaction -> finishedLatch1.countDown()); int startSyncId2 = mSurfaceSyncer.setupSync(transaction -> finishedLatch2.countDown()); - Syncable syncable1 = new Syncable(); - Syncable syncable2 = new Syncable(); + SyncTarget syncTarget1 = new SyncTarget(); + SyncTarget syncTarget2 = new SyncTarget(); - assertTrue(mSurfaceSyncer.addToSync(startSyncId1, syncable1)); - assertTrue(mSurfaceSyncer.addToSync(startSyncId2, syncable2)); + assertTrue(mSurfaceSyncer.addToSync(startSyncId1, syncTarget1)); + assertTrue(mSurfaceSyncer.addToSync(startSyncId2, syncTarget2)); mSurfaceSyncer.markSyncReady(startSyncId1); mSurfaceSyncer.markSyncReady(startSyncId2); - syncable1.onBufferReady(); + syncTarget1.onBufferReady(); finishedLatch1.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch1.getCount()); assertNotEquals(0, finishedLatch2.getCount()); - syncable2.onBufferReady(); + syncTarget2.onBufferReady(); finishedLatch2.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch2.getCount()); } - private static class Syncable implements SurfaceSyncer.SyncTarget { + @Test + public void testMergeSync() throws InterruptedException { + final CountDownLatch finishedLatch1 = new CountDownLatch(1); + final CountDownLatch finishedLatch2 = new CountDownLatch(1); + int startSyncId1 = mSurfaceSyncer.setupSync(transaction -> finishedLatch1.countDown()); + int startSyncId2 = mSurfaceSyncer.setupSync(transaction -> finishedLatch2.countDown()); + + SyncTarget syncTarget1 = new SyncTarget(); + SyncTarget syncTarget2 = new SyncTarget(); + + assertTrue(mSurfaceSyncer.addToSync(startSyncId1, syncTarget1)); + assertTrue(mSurfaceSyncer.addToSync(startSyncId2, syncTarget2)); + mSurfaceSyncer.markSyncReady(startSyncId1); + mSurfaceSyncer.merge(startSyncId2, startSyncId1, mSurfaceSyncer); + mSurfaceSyncer.markSyncReady(startSyncId2); + + // Finish syncTarget2 first to test that the syncSet is not complete until the merged sync + // is also done. + syncTarget2.onBufferReady(); + finishedLatch2.await(1, TimeUnit.SECONDS); + // Sync did not complete yet + assertNotEquals(0, finishedLatch2.getCount()); + + syncTarget1.onBufferReady(); + + // The first sync will still get a callback when it's sync requirements are done. + finishedLatch1.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch1.getCount()); + + finishedLatch2.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch2.getCount()); + } + + @Test + public void testMergeSyncAlreadyComplete() throws InterruptedException { + final CountDownLatch finishedLatch1 = new CountDownLatch(1); + final CountDownLatch finishedLatch2 = new CountDownLatch(1); + int startSyncId1 = mSurfaceSyncer.setupSync(transaction -> finishedLatch1.countDown()); + int startSyncId2 = mSurfaceSyncer.setupSync(transaction -> finishedLatch2.countDown()); + + SyncTarget syncTarget1 = new SyncTarget(); + SyncTarget syncTarget2 = new SyncTarget(); + + assertTrue(mSurfaceSyncer.addToSync(startSyncId1, syncTarget1)); + assertTrue(mSurfaceSyncer.addToSync(startSyncId2, syncTarget2)); + mSurfaceSyncer.markSyncReady(startSyncId1); + syncTarget1.onBufferReady(); + + // The first sync will still get a callback when it's sync requirements are done. + finishedLatch1.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch1.getCount()); + + mSurfaceSyncer.merge(startSyncId2, startSyncId1, mSurfaceSyncer); + mSurfaceSyncer.markSyncReady(startSyncId2); + syncTarget2.onBufferReady(); + + // Verify that the second sync will receive complete since the merged sync was already + // completed before the merge. + finishedLatch2.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch2.getCount()); + } + + private static class SyncTarget implements SurfaceSyncer.SyncTarget { private SurfaceSyncer.SyncBufferCallback mSyncBufferCallback; @Override |