Merge "[MediaProjection] Secure aidl interfaces with permission checks"

This commit is contained in:
Naomi Musgrave
2023-03-29 17:35:52 +00:00
committed by Android (Google) Code Review
5 changed files with 71 additions and 17 deletions

View File

@@ -23,22 +23,32 @@ import android.os.IBinder;
interface IMediaProjection {
void start(IMediaProjectionCallback callback);
void stop();
boolean canProjectAudio();
boolean canProjectVideo();
boolean canProjectSecureVideo();
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
int applyVirtualDisplayFlags(int flags);
void registerCallback(IMediaProjectionCallback callback);
void unregisterCallback(IMediaProjectionCallback callback);
/**
* Returns the {@link android.os.IBinder} identifying the task to record, or {@code null} if
* there is none.
*/
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
IBinder getLaunchCookie();
/**
* Updates the {@link android.os.IBinder} identifying the task to record, or {@code null} if
* there is none.
*/
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
void setLaunchCookie(in IBinder launchCookie);
}

View File

@@ -28,28 +28,34 @@ interface IMediaProjectionManager {
@UnsupportedAppUsage
boolean hasProjectionPermission(int uid, String packageName);
/**
* Returns a new {@link IMediaProjection} instance associated with the given package.
*/
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
IMediaProjection createProjection(int uid, String packageName, int type,
boolean permanentGrant);
/**
* Returns {@code true} if the given {@link IMediaProjection} corresponds to the current
* projection, or {@code false} otherwise.
*/
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
boolean isCurrentProjection(IMediaProjection projection);
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
MediaProjectionInfo getActiveProjectionInfo();
@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);
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible);
@@ -70,6 +76,8 @@ interface IMediaProjectionManager {
* @param incomingSession the nullable incoming content recording session
* @param projection the non-null projection the session describes
*/
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
void setContentRecordingSession(in ContentRecordingSession incomingSession,
in IMediaProjection projection);
}

View File

@@ -11599,6 +11599,7 @@ public class AudioService extends IAudioService.Stub
return false;
}
final long token = Binder.clearCallingIdentity();
try {
if (!projectionService.isCurrentProjection(projection)) {
Log.w(TAG, "App passed invalid MediaProjection token");
@@ -11608,6 +11609,8 @@ public class AudioService extends IAudioService.Stub
Log.e(TAG, "Can't call .isCurrentProjection() on IMediaProjectionManager"
+ projectionService.asBinder(), e);
return false;
} finally {
Binder.restoreCallingIdentity(token);
}
try {

View File

@@ -1419,6 +1419,7 @@ public final class DisplayManagerService extends SystemService {
}
if (projection != null) {
final long firstToken = Binder.clearCallingIdentity();
try {
if (!getProjectionService().isCurrentProjection(projection)) {
throw new SecurityException("Cannot create VirtualDisplay with "
@@ -1427,6 +1428,8 @@ public final class DisplayManagerService extends SystemService {
flags = projection.applyVirtualDisplayFlags(flags);
} catch (RemoteException e) {
throw new SecurityException("unable to validate media projection or flags");
} finally {
Binder.restoreCallingIdentity(firstToken);
}
}
@@ -1494,7 +1497,7 @@ public final class DisplayManagerService extends SystemService {
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
final long token = Binder.clearCallingIdentity();
final long secondToken = Binder.clearCallingIdentity();
try {
final int displayId;
synchronized (mSyncRoot) {
@@ -1566,7 +1569,7 @@ public final class DisplayManagerService extends SystemService {
return displayId;
} finally {
Binder.restoreCallingIdentity(token);
Binder.restoreCallingIdentity(secondToken);
}
}

View File

@@ -16,6 +16,7 @@
package com.android.server.media.projection;
import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED;
import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED;
@@ -282,7 +283,7 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
public IMediaProjection createProjection(int uid, String packageName, int type,
boolean isPermanentGrant) {
if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to grant "
+ "projection permission");
@@ -314,16 +315,21 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
public boolean isCurrentProjection(IMediaProjection projection) {
if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to check "
+ "if the given projection is current.");
}
return MediaProjectionManagerService.this.isCurrentProjection(
projection == null ? null : projection.asBinder());
}
@Override // Binder call
public MediaProjectionInfo getActiveProjectionInfo() {
if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
+ "projection callbacks");
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to get "
+ "active projection info");
}
final long token = Binder.clearCallingIdentity();
try {
@@ -333,10 +339,13 @@ public final class MediaProjectionManagerService extends SystemService
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
public void stopActiveProjection() {
stopActiveProjection_enforcePermission();
if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to stop "
+ "the active projection");
}
final long token = Binder.clearCallingIdentity();
try {
if (mProjectionGrant != null) {
@@ -347,10 +356,13 @@ 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();
if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to notify "
+ "on captured content resize");
}
if (!isCurrentProjection(mProjectionGrant)) {
return;
}
@@ -364,10 +376,13 @@ public final class MediaProjectionManagerService extends SystemService
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override
public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) {
notifyActiveProjectionCapturedContentVisibilityChanged_enforcePermission();
if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to notify "
+ "on captured content visibility changed");
}
if (!isCurrentProjection(mProjectionGrant)) {
return;
}
@@ -383,7 +398,7 @@ public final class MediaProjectionManagerService extends SystemService
@Override //Binder call
public void addCallback(final IMediaProjectionWatcherCallback callback) {
if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
+ "projection callbacks");
@@ -398,7 +413,7 @@ public final class MediaProjectionManagerService extends SystemService
@Override
public void removeCallback(IMediaProjectionWatcherCallback callback) {
if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to remove "
+ "projection callbacks");
@@ -503,6 +518,11 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
public int applyVirtualDisplayFlags(int flags) {
if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION to apply virtual "
+ "display flags.");
}
if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) {
flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
@@ -651,11 +671,21 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
public void setLaunchCookie(IBinder launchCookie) {
if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION to set launch "
+ "cookie.");
}
mLaunchCookie = launchCookie;
}
@Override // Binder call
public IBinder getLaunchCookie() {
if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION to get launch "
+ "cookie.");
}
return mLaunchCookie;
}