diff options
19 files changed, 536 insertions, 155 deletions
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl index 8ee966ddc377..dacd1bd06cc0 100644 --- a/media/java/android/media/projection/IMediaProjection.aidl +++ b/media/java/android/media/projection/IMediaProjection.aidl @@ -17,13 +17,14 @@ package android.media.projection; import android.media.projection.IMediaProjectionCallback; +import android.media.projection.StopReason; import android.os.IBinder; import android.app.ActivityOptions.LaunchCookie; /** {@hide} */ interface IMediaProjection { void start(IMediaProjectionCallback callback); - void stop(); + void stop(StopReason stopReason); boolean canProjectAudio(); boolean canProjectVideo(); diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl index b104972572b9..1d92eabb726d 100644 --- a/media/java/android/media/projection/IMediaProjectionManager.aidl +++ b/media/java/android/media/projection/IMediaProjectionManager.aidl @@ -16,11 +16,13 @@ package android.media.projection; +import android.graphics.Rect; import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionCallback; import android.media.projection.IMediaProjectionWatcherCallback; import android.media.projection.MediaProjectionInfo; import android.media.projection.ReviewGrantedConsentResult; +import android.media.projection.StopReason; import android.os.IBinder; import android.view.ContentRecordingSession; @@ -107,12 +109,7 @@ interface IMediaProjectionManager { @EnforcePermission("MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - void stopActiveProjection(); - - @EnforcePermission("MANAGE_MEDIA_PROJECTION") - @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" - + ".permission.MANAGE_MEDIA_PROJECTION)") - void notifyActiveProjectionCapturedContentResized(int width, int height); + void stopActiveProjection(in StopReason stopReason); @EnforcePermission("MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" @@ -227,5 +224,11 @@ interface IMediaProjectionManager { @EnforcePermission("MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode); + oneway void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode); + + @EnforcePermission("MANAGE_MEDIA_PROJECTION") + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MANAGE_MEDIA_PROJECTION)") + oneway void notifyCaptureBoundsChanged(int contentToRecord, int targetProcessUid, + in Rect captureBounds); } diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java index 4114f5359ace..f7f10df5786a 100644 --- a/media/java/android/media/projection/MediaProjection.java +++ b/media/java/android/media/projection/MediaProjection.java @@ -317,7 +317,7 @@ public final class MediaProjection { public void stop() { try { Log.d(TAG, "Content Recording: stopping projection"); - mImpl.stop(); + mImpl.stop(StopReason.STOP_HOST_APP); } catch (RemoteException e) { Log.e(TAG, "Unable to stop projection", e); } diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java index dc55e41fb74c..9cc2cca441a4 100644 --- a/media/java/android/media/projection/MediaProjectionManager.java +++ b/media/java/android/media/projection/MediaProjectionManager.java @@ -297,10 +297,10 @@ public final class MediaProjectionManager { * Stop the current projection if there is one. * @hide */ - public void stopActiveProjection() { + public void stopActiveProjection(@StopReason int stopReason) { try { Log.d(TAG, "Content Recording: stopping active projection"); - mService.stopActiveProjection(); + mService.stopActiveProjection(stopReason); } catch (RemoteException e) { Log.e(TAG, "Unable to stop the currently active media projection", e); } diff --git a/media/java/android/media/projection/StopReason.aidl b/media/java/android/media/projection/StopReason.aidl new file mode 100644 index 000000000000..8611def3d2b9 --- /dev/null +++ b/media/java/android/media/projection/StopReason.aidl @@ -0,0 +1,36 @@ +/* + * 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 android.media.projection; + +/** + * Identifies the reason for a MediaProjection being stopped (for metric logging purposes) + * @hide + */ +@Backing(type="int") +enum StopReason { + STOP_UNKNOWN = 0, + STOP_HOST_APP = 1, + STOP_TARGET_REMOVED = 2, + STOP_DEVICE_LOCKED = 3, + STOP_PRIVACY_CHIP = 4, + STOP_QS_TILE = 5, + STOP_USER_SWITCH = 6, + STOP_FOREGROUND_SERVICE_CHANGE = 7, + STOP_NEW_PROJECTION = 8, + STOP_NEW_MEDIA_ROUTE = 9, + STOP_ERROR = 10, +} diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java index c9807e626429..58aa56babb64 100644 --- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java +++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java @@ -46,7 +46,7 @@ public final class FakeIMediaProjection extends IMediaProjection.Stub { } @Override - public void stop() throws RemoteException { + public void stop(@StopReason int stopReason) throws RemoteException { // Pass along to the client's callback wrapper. mIMediaProjectionCallback.onStop(); } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt index 02825a55923f..ff00bfb540c6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.mediaprojection.data.repository import android.hardware.display.displayManager import android.media.projection.MediaProjectionInfo +import android.media.projection.StopReason import android.os.Binder import android.os.Handler import android.os.UserHandle @@ -339,8 +340,9 @@ class MediaProjectionManagerRepositoryTest : SysuiTestCase() { @Test fun stopProjecting_invokesManager() = testScope.runTest { - repo.stopProjecting() + repo.stopProjecting(StopReason.STOP_QS_TILE) - verify(fakeMediaProjectionManager.mediaProjectionManager).stopActiveProjection() + verify(fakeMediaProjectionManager.mediaProjectionManager) + .stopActiveProjection(StopReason.STOP_QS_TILE) } } diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt index 35efd751b8fe..7d3094827e17 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt @@ -20,6 +20,7 @@ import android.app.ActivityManager.RunningTaskInfo import android.hardware.display.DisplayManager import android.media.projection.MediaProjectionInfo import android.media.projection.MediaProjectionManager +import android.media.projection.StopReason import android.os.Handler import android.view.ContentRecordingSession import android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY @@ -72,7 +73,7 @@ constructor( } } - override suspend fun stopProjecting() { + override suspend fun stopProjecting(@StopReason stopReason: Int) { withContext(backgroundDispatcher) { logger.log( TAG, @@ -80,7 +81,7 @@ constructor( {}, { "Requesting MediaProjectionManager#stopActiveProjection" }, ) - mediaProjectionManager.stopActiveProjection() + mediaProjectionManager.stopActiveProjection(stopReason) } } diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt index 50182d7a3b33..a01d8c2c98de 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt @@ -17,6 +17,7 @@ package com.android.systemui.mediaprojection.data.repository import android.app.ActivityManager.RunningTaskInfo +import android.media.projection.StopReason import com.android.systemui.mediaprojection.data.model.MediaProjectionState import kotlinx.coroutines.flow.Flow @@ -27,7 +28,7 @@ interface MediaProjectionRepository { suspend fun switchProjectedTask(task: RunningTaskInfo) /** Stops the currently active projection. */ - suspend fun stopProjecting() + suspend fun stopProjecting(@StopReason stopReason: Int) /** Represents the current [MediaProjectionState]. */ val mediaProjectionState: Flow<MediaProjectionState> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt index af238f697a18..49c44798d2ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor import android.content.pm.PackageManager +import android.media.projection.StopReason import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton @@ -105,7 +106,7 @@ constructor( /** Stops the currently active projection. */ fun stopProjecting() { - scope.launch { mediaProjectionRepository.stopProjecting() } + scope.launch { mediaProjectionRepository.stopProjecting(StopReason.STOP_PRIVACY_CHIP) } } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java index a115baad257d..52f80fbf50fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java @@ -24,6 +24,7 @@ import android.media.MediaRouter; import android.media.MediaRouter.RouteInfo; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; +import android.media.projection.StopReason; import android.os.Handler; import android.util.ArrayMap; @@ -190,7 +191,7 @@ public class CastControllerImpl implements CastController { if (isProjection) { final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag(); if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) { - mProjectionManager.stopActiveProjection(); + mProjectionManager.stopActiveProjection(StopReason.STOP_QS_TILE); } else { mLogger.logStopCastingNoProjection(projection); } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt index d631f926176d..e6256a58a365 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt @@ -17,6 +17,7 @@ package com.android.systemui.mediaprojection.data.repository import android.app.ActivityManager +import android.media.projection.StopReason import com.android.systemui.mediaprojection.data.model.MediaProjectionState import kotlinx.coroutines.flow.MutableStateFlow @@ -28,7 +29,7 @@ class FakeMediaProjectionRepository : MediaProjectionRepository { var stopProjectingInvoked = false - override suspend fun stopProjecting() { + override suspend fun stopProjecting(@StopReason stopReason: Int) { stopProjectingInvoked = true } } diff --git a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java index 6c74cba99bcb..05fe78114eca 100644 --- a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java +++ b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java @@ -30,7 +30,8 @@ public class FrameworkStatsLogWrapper { int hostUid, int targetUid, int timeSinceLastActive, - int creationSource) { + int creationSource, + int stopSource) { FrameworkStatsLog.write( code, sessionId, @@ -39,7 +40,8 @@ public class FrameworkStatsLogWrapper { hostUid, targetUid, timeSinceLastActive, - creationSource); + creationSource, + stopSource); } /** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionTargetChanged atom. */ @@ -49,13 +51,23 @@ public class FrameworkStatsLogWrapper { int targetType, int hostUid, int targetUid, - int windowingMode) { + int windowingMode, + int width, + int height, + int centerX, + int centerY, + int targetChangeType) { FrameworkStatsLog.write( code, sessionId, targetType, hostUid, targetUid, - windowingMode); + windowingMode, + width, + height, + centerX, + centerY, + targetChangeType); } } diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index df5ecf872df4..c428f39fd9d0 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -51,6 +51,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.ApplicationInfoFlags; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ServiceInfo; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.media.MediaRouter; import android.media.projection.IMediaProjection; @@ -60,6 +61,7 @@ import android.media.projection.IMediaProjectionWatcherCallback; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; import android.media.projection.ReviewGrantedConsentResult; +import android.media.projection.StopReason; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -178,7 +180,7 @@ public final class MediaProjectionManagerService extends SystemService if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) { Slog.d(TAG, "Content Recording: Stopping MediaProjection due to " + MediaProjectionStopController.stopReasonToString(reason)); - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_DEVICE_LOCKED); } } } @@ -257,7 +259,7 @@ public final class MediaProjectionManagerService extends SystemService synchronized (mLock) { if (mProjectionGrant != null) { Slog.d(TAG, "Content Recording: Stopped MediaProjection due to user switching"); - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_USER_SWITCH); } } } @@ -295,7 +297,7 @@ public final class MediaProjectionManagerService extends SystemService Slog.d(TAG, "Content Recording: Stopped MediaProjection due to foreground service change"); if (mProjectionGrant != null) { - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_FOREGROUND_SERVICE_CHANGE); } } } @@ -304,7 +306,7 @@ public final class MediaProjectionManagerService extends SystemService if (mProjectionGrant != null) { Slog.d(TAG, "Content Recording: Stopped MediaProjection to start new " + "incoming projection"); - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_NEW_PROJECTION); } if (mMediaRouteInfo != null) { mMediaRouter.getFallbackRoute().select(); @@ -314,7 +316,10 @@ public final class MediaProjectionManagerService extends SystemService dispatchStart(projection); } - private void stopProjectionLocked(final MediaProjection projection) { + private void stopProjectionLocked( + final MediaProjection projection, + @StopReason int stopReason + ) { Slog.d(TAG, "Content Recording: Stopped active MediaProjection and " + "dispatching stop to callbacks"); ContentRecordingSession session = projection.mSession; @@ -322,7 +327,7 @@ public final class MediaProjectionManagerService extends SystemService session != null ? session.getTargetUid() : ContentRecordingSession.TARGET_UID_UNKNOWN; - mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid); + mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid, stopReason); mProjectionToken = null; mProjectionGrant = null; dispatchStop(projection); @@ -403,7 +408,7 @@ public final class MediaProjectionManagerService extends SystemService + "ContentRecordingSession - id= " + mProjectionGrant.getVirtualDisplayId() + "type=" + projectionType); - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_ERROR); } return false; } @@ -517,6 +522,18 @@ public final class MediaProjectionManagerService extends SystemService } } + @VisibleForTesting + void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds) { + synchronized (mLock) { + if (mProjectionGrant == null) { + Slog.i(TAG, "Cannot log MediaProjectionTargetChanged atom due to null projection"); + } else { + mMediaProjectionMetricsLogger.logChangedCaptureBounds( + contentToRecord, mProjectionGrant.uid, targetUid, captureBounds); + } + } + } + /** * Handles result of dialog shown from * {@link BinderService#buildReviewGrantedConsentIntentLocked()}. @@ -557,7 +574,7 @@ public final class MediaProjectionManagerService extends SystemService Slog.w(TAG, "Content Recording: Stopped MediaProjection due to user " + "consent result of CANCEL - " + "id= " + mProjectionGrant.getVirtualDisplayId()); - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_ERROR); } break; case RECORD_CONTENT_DISPLAY: @@ -773,14 +790,14 @@ public final class MediaProjectionManagerService extends SystemService @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION) @Override // Binder call - public void stopActiveProjection() { + public void stopActiveProjection(@StopReason int stopReason) { stopActiveProjection_enforcePermission(); final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { if (mProjectionGrant != null) { Slog.d(TAG, "Content Recording: Stopping active projection"); - mProjectionGrant.stop(); + mProjectionGrant.stop(stopReason); } } } finally { @@ -790,8 +807,9 @@ public final class MediaProjectionManagerService extends SystemService @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION) @Override // Binder call - public void notifyActiveProjectionCapturedContentResized(int width, int height) { - notifyActiveProjectionCapturedContentResized_enforcePermission(); + public void notifyCaptureBoundsChanged( + int contentToRecord, int targetProcessUid, Rect newBounds) { + notifyCaptureBoundsChanged_enforcePermission(); synchronized (mLock) { if (!isCurrentProjection(mProjectionGrant)) { return; @@ -801,7 +819,13 @@ public final class MediaProjectionManagerService extends SystemService try { synchronized (mLock) { if (mProjectionGrant != null && mCallbackDelegate != null) { - mCallbackDelegate.dispatchResize(mProjectionGrant, width, height); + // log metrics for the new bounds + MediaProjectionManagerService.this.notifyCaptureBoundsChanged( + contentToRecord, targetProcessUid, newBounds); + + // update clients of the new update bounds + mCallbackDelegate.dispatchResize( + mProjectionGrant, newBounds.width(), newBounds.height()); } } } finally { @@ -1133,7 +1157,7 @@ public final class MediaProjectionManagerService extends SystemService Slog.d(TAG, "Content Recording: MediaProjection stopped by Binder death - " + "id= " + mVirtualDisplayId); mCallbackDelegate.remove(callback); - stop(); + stop(StopReason.STOP_TARGET_REMOVED); }; mToken.linkToDeath(mDeathEater, 0); } catch (RemoteException e) { @@ -1182,7 +1206,7 @@ public final class MediaProjectionManagerService extends SystemService } @Override // Binder call - public void stop() { + public void stop(@StopReason int stopReason) { synchronized (mLock) { if (!isCurrentProjection(asBinder())) { Slog.w(TAG, "Attempted to stop inactive MediaProjection " @@ -1211,7 +1235,7 @@ public final class MediaProjectionManagerService extends SystemService Slog.d(TAG, "Content Recording: handling stopping this projection token" + " createTime= " + mCreateTimeMillis + " countStarts= " + mCountStarts); - stopProjectionLocked(this); + stopProjectionLocked(this, stopReason); mToken.unlinkToDeath(mDeathEater, 0); mToken = null; unregisterCallback(mCallback); @@ -1295,7 +1319,7 @@ public final class MediaProjectionManagerService extends SystemService Slog.v(TAG, "Reusing token: Throw exception due to invalid projection."); // Tear down projection here; necessary to ensure (among other reasons) that // stop is dispatched to client and cast icon disappears from status bar. - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_ERROR); throw new SecurityException("Don't re-use the resultData to retrieve " + "the same projection instance, and don't use a token that has " + "timed out. Don't take multiple captures by invoking " @@ -1315,10 +1339,9 @@ public final class MediaProjectionManagerService extends SystemService Slog.w(TAG, "Content Recording: MediaProjection start disallowed, aborting " + "MediaProjection"); - stop(); + stop(StopReason.STOP_DEVICE_LOCKED); return; } - mVirtualDisplayId = displayId; // If prior session was does not have a valid display id, then update the display @@ -1357,7 +1380,7 @@ public final class MediaProjectionManagerService extends SystemService if (mProjectionGrant != null) { Slog.d(TAG, "Content Recording: Stopped MediaProjection due to " + "route type of REMOTE_DISPLAY not selected"); - mProjectionGrant.stop(); + mProjectionGrant.stop(StopReason.STOP_NEW_MEDIA_ROUTE); } } } diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java index be2a25a755a5..8e5c01685275 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java @@ -19,15 +19,34 @@ package com.android.server.media.projection; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY; import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN; @@ -36,8 +55,12 @@ import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGE import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN; +import android.app.WindowConfiguration; import android.app.WindowConfiguration.WindowingMode; import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.media.projection.StopReason; import android.util.Log; import android.view.ContentRecordingSession.RecordContent; @@ -59,8 +82,10 @@ public class MediaProjectionMetricsLogger { private final MediaProjectionSessionIdGenerator mSessionIdGenerator; private final MediaProjectionTimestampStore mTimestampStore; - private int mPreviousState = - FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN; + private final Rect mPreviousTargetBounds = new Rect(); + private int mPreviousTargetWindowingMode = WINDOWING_MODE_UNDEFINED; + private int mPreviousProjectionState = + MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN; MediaProjectionMetricsLogger( FrameworkStatsLogWrapper frameworkStatsLogWrapper, @@ -113,7 +138,8 @@ public class MediaProjectionMetricsLogger { hostUid, TARGET_UID_UNKNOWN, timeSinceLastActiveInSeconds, - sessionCreationSource); + sessionCreationSource, + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); } /** @@ -130,7 +156,8 @@ public class MediaProjectionMetricsLogger { hostUid, TARGET_UID_UNKNOWN, TIME_SINCE_LAST_ACTIVE_UNKNOWN, - MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN); + MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN, + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); } /** @@ -141,13 +168,12 @@ public class MediaProjectionMetricsLogger { public void logProjectionPermissionRequestCancelled(int hostUid) { writeStateChanged( mSessionIdGenerator.getCurrentSessionId(), - FrameworkStatsLog - .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED, + MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED, hostUid, TARGET_UID_UNKNOWN, TIME_SINCE_LAST_ACTIVE_UNKNOWN, - FrameworkStatsLog - .MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN); + MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN, + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); } /** @@ -163,7 +189,8 @@ public class MediaProjectionMetricsLogger { hostUid, TARGET_UID_UNKNOWN, TIME_SINCE_LAST_ACTIVE_UNKNOWN, - MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN); + MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN, + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); } /** @@ -180,7 +207,8 @@ public class MediaProjectionMetricsLogger { hostUid, targetUid, TIME_SINCE_LAST_ACTIVE_UNKNOWN, - MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN); + MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN, + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); } /** @@ -196,14 +224,63 @@ public class MediaProjectionMetricsLogger { */ public void logChangedWindowingMode( int contentToRecord, int hostUid, int targetUid, int windowingMode) { - Log.d(TAG, "logChangedWindowingMode"); + Log.d(TAG, "logChangedWindowingMode: windowingMode= " + + WindowConfiguration.windowingModeToString(windowingMode)); + Log.d(TAG, "targetChangeType= changeWindowingMode"); writeTargetChanged( mSessionIdGenerator.getCurrentSessionId(), contentToRecordToTargetType(contentToRecord), hostUid, targetUid, - windowingModeToTargetWindowingMode(windowingMode)); + windowingModeToTargetWindowingMode(windowingMode), + mPreviousTargetBounds.width(), + mPreviousTargetBounds.height(), + mPreviousTargetBounds.centerX(), + mPreviousTargetBounds.centerY(), + MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE); + mPreviousTargetWindowingMode = windowingMode; + } + /** + * Logs that the bounds of projection's capture target has changed. + * + * @param contentToRecord ContentRecordingSession.RecordContent indicating whether it is a + * task capture or display capture - gets converted to the corresponding + * TargetType before being logged. + * @param hostUid UID of the package that initiates MediaProjection. + * @param targetUid UID of the package that is captured if selected. + * @param captureBounds Updated bounds of the captured region. + */ + public void logChangedCaptureBounds( + int contentToRecord, int hostUid, int targetUid, Rect captureBounds) { + final Point capturePosition = new Point(captureBounds.centerX(), captureBounds.centerY()); + Log.d(TAG, "logChangedCaptureBounds: captureBounds= " + captureBounds + " position= " + + capturePosition); + + writeTargetChanged( + mSessionIdGenerator.getCurrentSessionId(), + contentToRecordToTargetType(contentToRecord), + hostUid, + targetUid, + mPreviousTargetWindowingMode, + captureBounds.width(), + captureBounds.height(), + captureBounds.centerX(), + captureBounds.centerY(), + captureBoundsToTargetChangeType(captureBounds)); + mPreviousTargetBounds.set(captureBounds); + } + + private int captureBoundsToTargetChangeType(Rect captureBounds) { + final boolean hasChangedSize = captureBounds.width() != mPreviousTargetBounds.width() + && captureBounds.height() != mPreviousTargetBounds.height(); + + if (hasChangedSize) { + Log.d(TAG, "targetChangeType= changeBounds"); + return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS; + } + Log.d(TAG, "targetChangeType= changePosition"); + return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION; } @VisibleForTesting @@ -231,45 +308,85 @@ public class MediaProjectionMetricsLogger { }; } + @VisibleForTesting + public int stopReasonToSessionStopSource(@StopReason int stopReason) { + return switch (stopReason) { + case StopReason.STOP_HOST_APP -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP; + case StopReason.STOP_TARGET_REMOVED -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE; + case StopReason.STOP_DEVICE_LOCKED-> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK; + case StopReason.STOP_PRIVACY_CHIP -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP; + case StopReason.STOP_QS_TILE -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE; + case StopReason.STOP_USER_SWITCH -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH; + case StopReason.STOP_FOREGROUND_SERVICE_CHANGE -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE; + case StopReason.STOP_NEW_PROJECTION -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION; + case StopReason.STOP_NEW_MEDIA_ROUTE -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE; + case StopReason.STOP_ERROR -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR; + default -> + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN; + }; + } + /** * Logs that the capturing stopped, either normally or because of error. * * @param hostUid UID of the package that initiates MediaProjection. * @param targetUid UID of the package that is captured if selected. */ - public void logStopped(int hostUid, int targetUid) { + public void logStopped(int hostUid, int targetUid, int stopReason) { boolean wasCaptureInProgress = - mPreviousState + mPreviousProjectionState == MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS; - Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress); + Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress + + " stopReason=" + stopReason); writeStateChanged( mSessionIdGenerator.getCurrentSessionId(), MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED, hostUid, targetUid, TIME_SINCE_LAST_ACTIVE_UNKNOWN, - MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN); + MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN, + stopReasonToSessionStopSource(stopReason)); if (wasCaptureInProgress) { mTimestampStore.registerActiveSessionEnded(); } } - public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) { - writeStateChanged(hostUid, state, sessionCreationSource); + public void notifyProjectionStateChange( + int hostUid, + int state, + int sessionCreationSource, + int sessionStopSource + ) { + writeStateChanged(hostUid, state, sessionCreationSource, sessionStopSource); } - private void writeStateChanged(int hostUid, int state, int sessionCreationSource) { + private void writeStateChanged( + int hostUid, + int state, + int sessionCreationSource, + int sessionStopSource + ) { mFrameworkStatsLogWrapper.writeStateChanged( - /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED, + /* code */ MEDIA_PROJECTION_STATE_CHANGED, /* session_id */ 123, /* state */ state, - /* previous_state */ FrameworkStatsLog - .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN, + /* previous_state */ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN, /* host_uid */ hostUid, /* target_uid */ -1, /* time_since_last_active */ 0, - /* creation_source */ sessionCreationSource); + /* creation_source */ sessionCreationSource, + /* stop_source */ sessionStopSource); } private void writeStateChanged( @@ -278,17 +395,19 @@ public class MediaProjectionMetricsLogger { int hostUid, int targetUid, int timeSinceLastActive, - int creationSource) { + int creationSource, + int stopSource) { mFrameworkStatsLogWrapper.writeStateChanged( - /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED, + /* code */ MEDIA_PROJECTION_STATE_CHANGED, sessionId, state, - mPreviousState, + mPreviousProjectionState, hostUid, targetUid, timeSinceLastActive, - creationSource); - mPreviousState = state; + creationSource, + stopSource); + mPreviousProjectionState = state; } private void writeTargetChanged( @@ -296,13 +415,23 @@ public class MediaProjectionMetricsLogger { int targetType, int hostUid, int targetUid, - int targetWindowingMode) { + int targetWindowingMode, + int width, + int height, + int centerX, + int centerY, + int targetChangeType) { mFrameworkStatsLogWrapper.writeTargetChanged( - /* code */ FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED, + /* code */ MEDIA_PROJECTION_TARGET_CHANGED, sessionId, targetType, hostUid, targetUid, - targetWindowingMode); + targetWindowingMode, + width, + height, + centerX, + centerY, + targetChangeType); } } diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java index 0b5872b3e601..93ccd74c6b23 100644 --- a/services/core/java/com/android/server/wm/ContentRecorder.java +++ b/services/core/java/com/android/server/wm/ContentRecorder.java @@ -32,6 +32,7 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.media.projection.IMediaProjectionManager; +import android.media.projection.StopReason; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -226,6 +227,7 @@ final class ContentRecorder implements WindowContainerListener { + "size %s", mDisplayContent.getDisplayId(), recordedContentBounds, recordedContentOrientation, surfaceSize); + updateMirroredSurface(mRecordedWindowContainer.getSyncTransaction(), recordedContentBounds, surfaceSize); } else { @@ -295,12 +297,12 @@ final class ContentRecorder implements WindowContainerListener { * Ensure recording does not fall back to the display stack; ensure the recording is stopped * and the client notified by tearing down the virtual display. */ - private void stopMediaProjection() { + private void stopMediaProjection(@StopReason int stopReason) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId()); if (mMediaProjectionManager != null) { - mMediaProjectionManager.stopActiveProjection(); + mMediaProjectionManager.stopActiveProjection(stopReason); } } @@ -507,7 +509,7 @@ final class ContentRecorder implements WindowContainerListener { if (shouldExitTaskRecording) { // Clean up the cached session first to ensure recording doesn't re-start, since // tearing down the display will generate display events which will trickle back here. - stopMediaProjection(); + stopMediaProjection(StopReason.STOP_ERROR); } } @@ -599,9 +601,13 @@ final class ContentRecorder implements WindowContainerListener { mLastRecordedBounds = new Rect(recordedContentBounds); mLastConsumingSurfaceSize.x = surfaceSize.x; mLastConsumingSurfaceSize.y = surfaceSize.y; - // Request to notify the client about the resize. - mMediaProjectionManager.notifyActiveProjectionCapturedContentResized( - mLastRecordedBounds.width(), mLastRecordedBounds.height()); + + // Request to notify the client about the updated bounds. + mMediaProjectionManager.notifyCaptureBoundsChanged( + mContentRecordingSession.getContentToRecord(), + mContentRecordingSession.getTargetUid(), + mLastRecordedBounds + ); } /** @@ -641,7 +647,7 @@ final class ContentRecorder implements WindowContainerListener { clearContentRecordingSession(); // Clean up the cached session first to ensure recording doesn't re-start, since // tearing down the display will generate display events which will trickle back here. - stopMediaProjection(); + stopMediaProjection(StopReason.STOP_TARGET_REMOVED); } // WindowContainerListener @@ -674,10 +680,10 @@ final class ContentRecorder implements WindowContainerListener { } @VisibleForTesting interface MediaProjectionManagerWrapper { - void stopActiveProjection(); - void notifyActiveProjectionCapturedContentResized(int width, int height); + void stopActiveProjection(@StopReason int stopReason); void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible); void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode); + void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds); } private static final class RemoteMediaProjectionManagerWrapper implements @@ -691,7 +697,7 @@ final class ContentRecorder implements WindowContainerListener { } @Override - public void stopActiveProjection() { + public void stopActiveProjection(@StopReason int stopReason) { fetchMediaProjectionManager(); if (mIMediaProjectionManager == null) { return; @@ -700,7 +706,7 @@ final class ContentRecorder implements WindowContainerListener { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Content Recording: stopping active projection for display %d", mDisplayId); - mIMediaProjectionManager.stopActiveProjection(); + mIMediaProjectionManager.stopActiveProjection(stopReason); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Content Recording: Unable to tell MediaProjectionManagerService to stop " @@ -710,52 +716,51 @@ final class ContentRecorder implements WindowContainerListener { } @Override - public void notifyActiveProjectionCapturedContentResized(int width, int height) { + public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) { fetchMediaProjectionManager(); if (mIMediaProjectionManager == null) { return; } try { - mIMediaProjectionManager.notifyActiveProjectionCapturedContentResized(width, - height); + mIMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged( + isVisible); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Content Recording: Unable to tell MediaProjectionManagerService about " - + "resizing the active projection: %s", + + "visibility change on the active projection: %s", e); } } @Override - public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) { + public void notifyWindowingModeChanged(int contentToRecord, int targetUid, + int windowingMode) { fetchMediaProjectionManager(); if (mIMediaProjectionManager == null) { return; } try { - mIMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged( - isVisible); + mIMediaProjectionManager.notifyWindowingModeChanged( + contentToRecord, targetUid, windowingMode); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, - "Content Recording: Unable to tell MediaProjectionManagerService about " - + "visibility change on the active projection: %s", - e); + "Content Recording: Unable to tell log windowing mode change: %s", e); } } @Override - public void notifyWindowingModeChanged(int contentToRecord, int targetUid, - int windowingMode) { + public void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, + Rect captureBounds) { fetchMediaProjectionManager(); if (mIMediaProjectionManager == null) { return; } try { - mIMediaProjectionManager.notifyWindowingModeChanged( - contentToRecord, targetUid, windowingMode); + mIMediaProjectionManager.notifyCaptureBoundsChanged( + contentToRecord, targetUid, captureBounds); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, - "Content Recording: Unable to tell log windowing mode change: %s", e); + "Content Recording: Unable to tell log bounds change: %s", e); } } diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java index b2a7d20fb948..3ced56a04138 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java @@ -67,10 +67,12 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.ApplicationInfoFlags; import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.Rect; import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionCallback; import android.media.projection.IMediaProjectionWatcherCallback; import android.media.projection.ReviewGrantedConsentResult; +import android.media.projection.StopReason; import android.os.Binder; import android.os.IBinder; import android.os.Looper; @@ -549,7 +551,7 @@ public class MediaProjectionManagerServiceTest { MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(service); - projection.stop(); + projection.stop(StopReason.STOP_UNKNOWN); verifyZeroInteractions(mMediaProjectionMetricsLogger); } @@ -562,10 +564,10 @@ public class MediaProjectionManagerServiceTest { startProjectionPreconditions(service); projection.start(mIMediaProjectionCallback); - projection.stop(); + final @StopReason int stopReason = StopReason.STOP_UNKNOWN; + projection.stop(stopReason); - verify(mMediaProjectionMetricsLogger) - .logStopped(UID, TARGET_UID_UNKNOWN); + verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN, stopReason); } @Test @@ -580,15 +582,16 @@ public class MediaProjectionManagerServiceTest { .setContentRecordingSession(any(ContentRecordingSession.class)); service.setContentRecordingSession(DISPLAY_SESSION); - projection.stop(); + final @StopReason int stopReason = StopReason.STOP_UNKNOWN; + projection.stop(stopReason); - verify(mMediaProjectionMetricsLogger) - .logStopped(UID, TARGET_UID_FULL_SCREEN); + verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_FULL_SCREEN, stopReason); } @Test public void stop_taskSession_logsHostUidAndTargetUid() throws Exception { int targetUid = 1234; + int stopReason = StopReason.STOP_UNKNOWN; MediaProjectionManagerService service = new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector); MediaProjectionManagerService.MediaProjection projection = @@ -601,9 +604,9 @@ public class MediaProjectionManagerServiceTest { taskSession.setTargetUid(targetUid); service.setContentRecordingSession(taskSession); - projection.stop(); + projection.stop(stopReason); - verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid); + verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid, stopReason); } @Test @@ -638,7 +641,7 @@ public class MediaProjectionManagerServiceTest { projection.start(mIMediaProjectionCallback); assertThat(projection.isValid()).isTrue(); - projection.stop(); + projection.stop(StopReason.STOP_UNKNOWN); // Second start - so not valid. projection.start(mIMediaProjectionCallback); @@ -692,7 +695,7 @@ public class MediaProjectionManagerServiceTest { MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions( service); projection.start(mIMediaProjectionCallback); - projection.stop(); + projection.stop(StopReason.STOP_UNKNOWN); // Second start - so not valid. projection.start(mIMediaProjectionCallback); @@ -708,7 +711,7 @@ public class MediaProjectionManagerServiceTest { MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions( service); projection.start(mIMediaProjectionCallback); - projection.stop(); + projection.stop(StopReason.STOP_UNKNOWN); // Second start - so not valid. projection.start(mIMediaProjectionCallback); @@ -947,6 +950,26 @@ public class MediaProjectionManagerServiceTest { projection.uid, targetUid, WINDOWING_MODE_MULTI_WINDOW); } + @Test + public void notifyCaptureBoundsChanged_forwardsToLoggerAndResizeCallbacks() throws Exception { + int targetUid = 123; + mService = + new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector); + + ContentRecordingSession taskSession = createTaskSession(mock(IBinder.class)); + taskSession.setTargetUid(targetUid); + mService.setContentRecordingSession(taskSession); + + MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(); + projection.start(mIMediaProjectionCallback); + + Rect newBounds = new Rect(0, 0, 1000, 2000); + mService.notifyCaptureBoundsChanged(RECORD_CONTENT_TASK, targetUid, newBounds); + + verify(mMediaProjectionMetricsLogger) + .logChangedCaptureBounds(RECORD_CONTENT_TASK, projection.uid, targetUid, newBounds); + } + /** * Executes and validates scenario where the consent result indicates the projection ends. */ diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java index 72ce9fe9a23f..c727bb6bbf7d 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java @@ -32,6 +32,17 @@ import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN; @@ -46,6 +57,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.media.projection.StopReason; import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -81,6 +93,7 @@ public class MediaProjectionMetricsLoggerTest { private static final int TEST_WINDOWING_MODE = 987; private static final int TEST_CONTENT_TO_RECORD = 654; + private static final int TEST_STOP_SOURCE = 321; @Mock private FrameworkStatsLogWrapper mFrameworkStatsLogWrapper; @Mock private MediaProjectionSessionIdGenerator mSessionIdGenerator; @@ -136,6 +149,14 @@ public class MediaProjectionMetricsLoggerTest { } @Test + public void logInitiated_logsUnknownStopSource() { + mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE); + + verifyStopSourceLogged( + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); + } + + @Test public void logInitiated_noPreviousSession_logsUnknownTimeSinceLastActive() { when(mTimestampStore.timeSinceLastActiveSession()).thenReturn(null); @@ -177,7 +198,7 @@ public class MediaProjectionMetricsLoggerTest { @Test public void logStopped_logsStateChangedAtomId() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifyStateChangedAtomIdLogged(); } @@ -187,42 +208,49 @@ public class MediaProjectionMetricsLoggerTest { int currentSessionId = 987; when(mSessionIdGenerator.getCurrentSessionId()).thenReturn(currentSessionId); - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifySessionIdLogged(currentSessionId); } @Test public void logStopped_logsStateStopped() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED); } @Test public void logStopped_logsHostUid() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifyStateChangedHostUidLogged(TEST_HOST_UID); } @Test public void logStopped_logsTargetUid() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifyStageChangedTargetUidLogged(TEST_TARGET_UID); } @Test + public void logStopped_logsStopSource() { + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, StopReason.STOP_UNKNOWN); + + verifyStopSourceLogged(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); + } + + @Test public void logStopped_logsUnknownTimeSinceLastActive() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifyTimeSinceLastActiveSessionLogged(-1); } @Test public void logStopped_logsUnknownSessionCreationSource() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifyCreationSourceLogged( MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN); @@ -230,7 +258,7 @@ public class MediaProjectionMetricsLoggerTest { @Test public void logStopped_logsPreviousState() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN); @@ -238,7 +266,7 @@ public class MediaProjectionMetricsLoggerTest { verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED); - mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE); + mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE); verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED); } @@ -247,14 +275,14 @@ public class MediaProjectionMetricsLoggerTest { public void logStopped_capturingWasInProgress_registersActiveSessionEnded() { mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID); - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verify(mTimestampStore).registerActiveSessionEnded(); } @Test public void logStopped_capturingWasNotInProgress_doesNotRegistersActiveSessionEnded() { - mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); + mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE); verify(mTimestampStore, never()).registerActiveSessionEnded(); } @@ -314,6 +342,14 @@ public class MediaProjectionMetricsLoggerTest { } @Test + public void logInProgress_logsUnknownSessionStopSource() { + mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID); + + verifyStopSourceLogged( + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); + } + + @Test public void logInProgress_logsPreviousState() { mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE); verifyPreviousStateLogged( @@ -323,7 +359,7 @@ public class MediaProjectionMetricsLoggerTest { verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED); - mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE); + mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE); verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS); @@ -387,6 +423,14 @@ public class MediaProjectionMetricsLoggerTest { } @Test + public void logPermissionRequestDisplayed_logsUnknownSessionStopSource() { + mLogger.logPermissionRequestDisplayed(TEST_HOST_UID); + + verifyStopSourceLogged( + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); + } + + @Test public void logPermissionRequestDisplayed_logsPreviousState() { mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE); verifyPreviousStateLogged( @@ -396,7 +440,7 @@ public class MediaProjectionMetricsLoggerTest { verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED); - mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE); + mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE); verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED); @@ -460,6 +504,14 @@ public class MediaProjectionMetricsLoggerTest { } @Test + public void logAppSelectorDisplayed_logsUnknownSessionStopSource() { + mLogger.logAppSelectorDisplayed(TEST_HOST_UID); + + verifyStopSourceLogged( + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); + } + + @Test public void logAppSelectorDisplayed_logsPreviousState() { mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE); verifyPreviousStateLogged( @@ -469,7 +521,7 @@ public class MediaProjectionMetricsLoggerTest { verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED); - mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE); + mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE); verifyPreviousStateLogged( MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED); @@ -536,6 +588,14 @@ public class MediaProjectionMetricsLoggerTest { } @Test + public void logProjectionPermissionRequestCancelled_logsUnknownStopSource() { + mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID); + + verifyStopSourceLogged( + MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); + } + + @Test public void logWindowingModeChanged_logsTargetChangedAtomId() { mLogger.logChangedWindowingMode( TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE); @@ -614,6 +674,42 @@ public class MediaProjectionMetricsLoggerTest { .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN); } + @Test + public void testStopReasonToSessionStopSource() { + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_HOST_APP)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_TARGET_REMOVED)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_DEVICE_LOCKED)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_PRIVACY_CHIP)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_QS_TILE)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_USER_SWITCH)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_FOREGROUND_SERVICE_CHANGE)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_PROJECTION)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_MEDIA_ROUTE)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_ERROR)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR); + + mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_UNKNOWN)) + .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN); + } + private void verifyStateChangedAtomIdLogged() { verify(mFrameworkStatsLogWrapper) .writeStateChanged( @@ -624,7 +720,8 @@ public class MediaProjectionMetricsLoggerTest { /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), /* timeSinceLastActive= */ anyInt(), - /* creationSource= */ anyInt()); + /* creationSource= */ anyInt(), + /* stopSource= */ anyInt()); } private void verifyStateLogged(int state) { @@ -637,7 +734,8 @@ public class MediaProjectionMetricsLoggerTest { /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), /* timeSinceLastActive= */ anyInt(), - /* creationSource= */ anyInt()); + /* creationSource= */ anyInt(), + /* stopSource= */ anyInt()); } private void verifyStateChangedHostUidLogged(int hostUid) { @@ -650,7 +748,8 @@ public class MediaProjectionMetricsLoggerTest { eq(hostUid), /* targetUid= */ anyInt(), /* timeSinceLastActive= */ anyInt(), - /* creationSource= */ anyInt()); + /* creationSource= */ anyInt(), + /* stopSource= */ anyInt()); } private void verifyCreationSourceLogged(int creationSource) { @@ -663,7 +762,22 @@ public class MediaProjectionMetricsLoggerTest { /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), /* timeSinceLastActive= */ anyInt(), - eq(creationSource)); + eq(creationSource), + /* stopSource= */ anyInt()); + } + + private void verifyStopSourceLogged(int stopSource) { + verify(mFrameworkStatsLogWrapper) + .writeStateChanged( + /* code= */ anyInt(), + /* sessionId= */ anyInt(), + /* state= */ anyInt(), + /* previousState= */ anyInt(), + /* hostUid= */ anyInt(), + /* targetUid= */ anyInt(), + /* timeSinceLastActive= */ anyInt(), + /* stopSource= */ anyInt(), + eq(stopSource)); } private void verifyStageChangedTargetUidLogged(int targetUid) { @@ -676,7 +790,8 @@ public class MediaProjectionMetricsLoggerTest { /* hostUid= */ anyInt(), eq(targetUid), /* timeSinceLastActive= */ anyInt(), - /* creationSource= */ anyInt()); + /* creationSource= */ anyInt(), + /* stopSource= */ anyInt()); } private void verifyTimeSinceLastActiveSessionLogged(int timeSinceLastActiveSession) { @@ -689,7 +804,8 @@ public class MediaProjectionMetricsLoggerTest { /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), /* timeSinceLastActive= */ eq(timeSinceLastActiveSession), - /* creationSource= */ anyInt()); + /* creationSource= */ anyInt(), + /* stopSource= */ anyInt()); } private void verifySessionIdLogged(int newSessionId) { @@ -702,7 +818,8 @@ public class MediaProjectionMetricsLoggerTest { /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), /* timeSinceLastActive= */ anyInt(), - /* creationSource= */ anyInt()); + /* creationSource= */ anyInt(), + /* stopSource= */ anyInt()); } private void verifyPreviousStateLogged(int previousState) { @@ -715,7 +832,8 @@ public class MediaProjectionMetricsLoggerTest { /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), /* timeSinceLastActive= */ anyInt(), - /* creationSource= */ anyInt()); + /* creationSource= */ anyInt(), + /* stopSource= */ anyInt()); } private void verifyTargetChangedAtomIdLogged() { @@ -726,7 +844,12 @@ public class MediaProjectionMetricsLoggerTest { /* targetType= */ anyInt(), /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), - /* targetWindowingMode= */ anyInt()); + /* targetWindowingMode= */ anyInt(), + /* width= */ anyInt(), + /* height= */ anyInt(), + /* centerX= */ anyInt(), + /* centerY= */ anyInt(), + /* targetChangeType= */ anyInt()); } private void verifyTargetTypeLogged(int targetType) { @@ -737,7 +860,12 @@ public class MediaProjectionMetricsLoggerTest { eq(targetType), /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), - /* targetWindowingMode= */ anyInt()); + /* targetWindowingMode= */ anyInt(), + /* width= */ anyInt(), + /* height= */ anyInt(), + /* centerX= */ anyInt(), + /* centerY= */ anyInt(), + /* targetChangeType= */ anyInt()); } private void verifyTargetChangedHostUidLogged(int hostUid) { @@ -748,7 +876,12 @@ public class MediaProjectionMetricsLoggerTest { /* targetType= */ anyInt(), eq(hostUid), /* targetUid= */ anyInt(), - /* targetWindowingMode= */ anyInt()); + /* targetWindowingMode= */ anyInt(), + /* width= */ anyInt(), + /* height= */ anyInt(), + /* centerX= */ anyInt(), + /* centerY= */ anyInt(), + /* targetChangeType= */ anyInt()); } private void verifyTargetChangedTargetUidLogged(int targetUid) { @@ -759,7 +892,12 @@ public class MediaProjectionMetricsLoggerTest { /* targetType= */ anyInt(), /* hostUid= */ anyInt(), eq(targetUid), - /* targetWindowingMode= */ anyInt()); + /* targetWindowingMode= */ anyInt(), + /* width= */ anyInt(), + /* height= */ anyInt(), + /* centerX= */ anyInt(), + /* centerY= */ anyInt(), + /* targetChangeType= */ anyInt()); } private void verifyWindowingModeLogged(int targetWindowingMode) { @@ -770,6 +908,11 @@ public class MediaProjectionMetricsLoggerTest { /* targetType= */ anyInt(), /* hostUid= */ anyInt(), /* targetUid= */ anyInt(), - eq(targetWindowingMode)); + eq(targetWindowingMode), + /* width= */ anyInt(), + /* height= */ anyInt(), + /* centerX= */ anyInt(), + /* centerY= */ anyInt(), + /* targetChangeType= */ anyInt()); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java index c51261f40ed5..76b994d013f3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java @@ -49,6 +49,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; +import android.media.projection.StopReason; import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.view.ContentRecordingSession; @@ -213,7 +214,7 @@ public class ContentRecorderTests extends WindowTestsBase { mContentRecorder.setContentRecordingSession(session); mContentRecorder.updateRecording(); assertThat(mContentRecorder.isCurrentlyRecording()).isFalse(); - verify(mMediaProjectionManagerWrapper).stopActiveProjection(); + verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR); } @Test @@ -225,7 +226,7 @@ public class ContentRecorderTests extends WindowTestsBase { mContentRecorder.setContentRecordingSession(invalidTaskSession); mContentRecorder.updateRecording(); assertThat(mContentRecorder.isCurrentlyRecording()).isFalse(); - verify(mMediaProjectionManagerWrapper).stopActiveProjection(); + verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR); } @Test @@ -310,8 +311,7 @@ public class ContentRecorderTests extends WindowTestsBase { mVirtualDisplayContent.getConfiguration().orientation, WINDOWING_MODE_FULLSCREEN); // No resize is issued, only the initial transformations when we started recording. - verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(), - anyFloat()); + verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat()); verify(mTransaction).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(), anyFloat(), anyFloat()); } @@ -386,19 +386,18 @@ public class ContentRecorderTests extends WindowTestsBase { // WHEN a configuration change arrives, and the recorded content is a different size. Configuration configuration = mTask.getConfiguration(); - configuration.windowConfiguration.setBounds(new Rect(0, 0, recordedWidth, recordedHeight)); - configuration.windowConfiguration.setAppBounds( - new Rect(0, 0, recordedWidth, recordedHeight)); + Rect newBounds = new Rect(0, 0, recordedWidth, recordedHeight); + configuration.windowConfiguration.setBounds(newBounds); + configuration.windowConfiguration.setAppBounds(newBounds); mTask.onConfigurationChanged(configuration); assertThat(mContentRecorder.isCurrentlyRecording()).isTrue(); // THEN content in the captured DisplayArea is scaled to fit the surface size. - verify(mTransaction, atLeastOnce()).setMatrix(eq(mRecordedSurface), anyFloat(), eq(0f), - eq(0f), - anyFloat()); + verify(mTransaction, atLeastOnce()).setMatrix( + eq(mRecordedSurface), anyFloat(), eq(0f), eq(0f), anyFloat()); // THEN the resize callback is notified. - verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized( - recordedWidth, recordedHeight); + verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged( + mTaskSession.getContentToRecord(), mTaskSession.getTargetUid(), newBounds); } @Test @@ -649,7 +648,7 @@ public class ContentRecorderTests extends WindowTestsBase { mTask.removeImmediately(); - verify(mMediaProjectionManagerWrapper).stopActiveProjection(); + verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_TARGET_REMOVED); } @Test @@ -684,8 +683,8 @@ public class ContentRecorderTests extends WindowTestsBase { int xInset = (mSurfaceSize.x - scaledWidth) / 2; verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0); // THEN the resize callback is notified. - verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized( - displayAreaBounds.width(), displayAreaBounds.height()); + verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged( + mDisplaySession.getContentToRecord(), mDisplaySession.getTargetUid(), displayAreaBounds); } @Test |