Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a582dde3 authored by dakinola's avatar dakinola Committed by Daniel Akinola
Browse files

Report MediaProjectionTargetChanged Atom

Update ContentRecorder & MediaProjectionManagerService to log a MediaProjectionTargetChanged atom upon recording starting and further updates to windowing mode.

Bug: 304728422
Test: atest WmTests:ContentRecorderTests
Test: atest FrameworksServicesTests:MediaProjectionManagerServiceTest
Test: atest FrameworksServicesTests:MediaProjectionMetricsLoggerTest
Change-Id: I5120ba2571fb2e6e084e72c4fd079767530ccdeb
parent 87e51c10
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2653,6 +2653,12 @@
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/TransitionController.java"
    },
    "261227010": {
      "message": "Content Recording: Unable to tell log windowing mode change: %s",
      "level": "ERROR",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "269576220": {
      "message": "Resuming rotation after drag",
      "level": "DEBUG",
+5 −0
Original line number Diff line number Diff line
@@ -212,4 +212,9 @@ interface IMediaProjectionManager {
    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
            + ".permission.MANAGE_MEDIA_PROJECTION)")
    oneway void notifyAppSelectorDisplayed(int hostUid);

    @EnforcePermission("MANAGE_MEDIA_PROJECTION")
    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
            + ".permission.MANAGE_MEDIA_PROJECTION)")
    void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode);
}
+19 −2
Original line number Diff line number Diff line
@@ -21,8 +21,8 @@ import com.android.internal.util.FrameworkStatsLog;
/** Wrapper around {@link FrameworkStatsLog} */
public class FrameworkStatsLogWrapper {

    /** Wrapper around {@link FrameworkStatsLog#write}. */
    public void write(
    /** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionStateChanged atom. */
    public void writeStateChanged(
            int code,
            int sessionId,
            int state,
@@ -41,4 +41,21 @@ public class FrameworkStatsLogWrapper {
                timeSinceLastActive,
                creationSource);
    }

    /** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionTargetChanged atom. */
    public void writeTargetChanged(
            int code,
            int sessionId,
            int targetType,
            int hostUid,
            int targetUid,
            int windowingMode) {
        FrameworkStatsLog.write(
                code,
                sessionId,
                targetType,
                hostUid,
                targetUid,
                windowingMode);
    }
}
+26 −0
Original line number Diff line number Diff line
@@ -479,6 +479,18 @@ public final class MediaProjectionManagerService extends SystemService
        mMediaProjectionMetricsLogger.logAppSelectorDisplayed(hostUid);
    }

    @VisibleForTesting
    void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode) {
        synchronized (mLock) {
            if (mProjectionGrant == null) {
                Slog.i(TAG, "Cannot log MediaProjectionTargetChanged atom due to null projection");
            } else {
                mMediaProjectionMetricsLogger.logChangedWindowingMode(
                        contentToRecord, mProjectionGrant.uid, targetUid, windowingMode);
            }
        }
    }

    /**
     * Handles result of dialog shown from
     * {@link BinderService#buildReviewGrantedConsentIntentLocked()}.
@@ -904,6 +916,20 @@ public final class MediaProjectionManagerService extends SystemService
            }
        }

        @Override // Binder call
        @EnforcePermission(MANAGE_MEDIA_PROJECTION)
        public void notifyWindowingModeChanged(
                int contentToRecord, int targetUid, int windowingMode) {
            notifyWindowingModeChanged_enforcePermission();
            final long token = Binder.clearCallingIdentity();
            try {
                MediaProjectionManagerService.this.notifyWindowingModeChanged(
                        contentToRecord, targetUid, windowingMode);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @Override // Binder call
        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+105 −9
Original line number Diff line number Diff line
@@ -16,16 +16,32 @@

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.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;

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_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;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FREEFORM;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FULLSCREEN;
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.WindowingMode;
import android.content.Context;
import android.util.Log;
import android.view.ContentRecordingSession.RecordContent;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;

import java.time.Duration;
@@ -91,7 +107,7 @@ public class MediaProjectionMetricsLogger {
                durationSinceLastActiveSession == null
                        ? TIME_SINCE_LAST_ACTIVE_UNKNOWN
                        : (int) durationSinceLastActiveSession.toSeconds();
        write(
        writeStateChanged(
                mSessionIdGenerator.createAndGetNewSessionId(),
                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED,
                hostUid,
@@ -102,13 +118,13 @@ public class MediaProjectionMetricsLogger {

    /**
     * Logs that the user entered the setup flow and permission dialog is displayed. This state is
     * not sent when the permission is already granted and we skipped showing the permission dialog.
     * not sent when the permission is already granted, and we skipped showing the permission dialog.
     *
     * @param hostUid UID of the package that initiates MediaProjection.
     */
    public void logPermissionRequestDisplayed(int hostUid) {
        Log.d(TAG, "logPermissionRequestDisplayed");
        write(
        writeStateChanged(
                mSessionIdGenerator.getCurrentSessionId(),
                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED,
                hostUid,
@@ -123,7 +139,7 @@ public class MediaProjectionMetricsLogger {
     * @param hostUid UID of the package that initiates MediaProjection.
     */
    public void logProjectionPermissionRequestCancelled(int hostUid) {
        write(
        writeStateChanged(
                mSessionIdGenerator.getCurrentSessionId(),
                FrameworkStatsLog
                        .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
@@ -141,7 +157,7 @@ public class MediaProjectionMetricsLogger {
     */
    public void logAppSelectorDisplayed(int hostUid) {
        Log.d(TAG, "logAppSelectorDisplayed");
        write(
        writeStateChanged(
                mSessionIdGenerator.getCurrentSessionId(),
                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED,
                hostUid,
@@ -158,7 +174,7 @@ public class MediaProjectionMetricsLogger {
     */
    public void logInProgress(int hostUid, int targetUid) {
        Log.d(TAG, "logInProgress");
        write(
        writeStateChanged(
                mSessionIdGenerator.getCurrentSessionId(),
                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS,
                hostUid,
@@ -167,6 +183,54 @@ public class MediaProjectionMetricsLogger {
                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
    }

    /**
     * Logs that the windowing mode of a projection 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 windowingMode Updated WindowConfiguration.WindowingMode of the captured region - gets
     *                      converted to the corresponding TargetWindowingMode before being logged.
     */
    public void logChangedWindowingMode(
            int contentToRecord, int hostUid, int targetUid, int windowingMode) {
        Log.d(TAG, "logChangedWindowingMode");
        writeTargetChanged(
                mSessionIdGenerator.getCurrentSessionId(),
                contentToRecordToTargetType(contentToRecord),
                hostUid,
                targetUid,
                windowingModeToTargetWindowingMode(windowingMode));

    }

    @VisibleForTesting
    public int contentToRecordToTargetType(@RecordContent int recordContentType) {
        return switch (recordContentType) {
            case RECORD_CONTENT_DISPLAY ->
                    MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY;
            case RECORD_CONTENT_TASK ->
                    MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK;
            default -> MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN;
        };
    }

    @VisibleForTesting
    public int windowingModeToTargetWindowingMode(@WindowingMode int windowingMode) {
        return switch (windowingMode) {
            case WINDOWING_MODE_FULLSCREEN ->
                    MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FULLSCREEN;
            case WINDOWING_MODE_FREEFORM ->
                    MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FREEFORM;
            case WINDOWING_MODE_MULTI_WINDOW ->
                    MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN;
            default ->
                    MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN;
        };
    }

    /**
     * Logs that the capturing stopped, either normally or because of error.
     *
@@ -178,7 +242,7 @@ public class MediaProjectionMetricsLogger {
                mPreviousState
                        == MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
        Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress);
        write(
        writeStateChanged(
                mSessionIdGenerator.getCurrentSessionId(),
                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED,
                hostUid,
@@ -191,14 +255,31 @@ public class MediaProjectionMetricsLogger {
        }
    }

    private void write(
    public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
        writeStateChanged(hostUid, state, sessionCreationSource);
    }

    private void writeStateChanged(int hostUid, int state, int sessionCreationSource) {
        mFrameworkStatsLogWrapper.writeStateChanged(
                /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
                /* session_id */ 123,
                /* state */ state,
                /* previous_state */ FrameworkStatsLog
                        .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
                /* host_uid */ hostUid,
                /* target_uid */ -1,
                /* time_since_last_active */ 0,
                /* creation_source */ sessionCreationSource);
    }

    private void writeStateChanged(
            int sessionId,
            int state,
            int hostUid,
            int targetUid,
            int timeSinceLastActive,
            int creationSource) {
        mFrameworkStatsLogWrapper.write(
        mFrameworkStatsLogWrapper.writeStateChanged(
                /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
                sessionId,
                state,
@@ -209,4 +290,19 @@ public class MediaProjectionMetricsLogger {
                creationSource);
        mPreviousState = state;
    }

    private void writeTargetChanged(
            int sessionId,
            int targetType,
            int hostUid,
            int targetUid,
            int targetWindowingMode) {
        mFrameworkStatsLogWrapper.writeTargetChanged(
                /* code */ FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED,
                sessionId,
                targetType,
                hostUid,
                targetUid,
                targetWindowingMode);
    }
}
Loading