Merge "Require a foreground service of a specific type to start media projection."
This commit is contained in:
committed by
Android (Google) Code Review
commit
3f95d3bc24
@@ -340,4 +340,21 @@ public abstract class ActivityManagerInternal {
|
||||
* like persisting database etc.
|
||||
*/
|
||||
public abstract void prepareForPossibleShutdown();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if {@code uid} is running a foreground service of a specific
|
||||
* {@code foregroundServiceType}.
|
||||
*/
|
||||
public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);
|
||||
|
||||
/**
|
||||
* Registers the specified {@code processObserver} to be notified of future changes to
|
||||
* process state.
|
||||
*/
|
||||
public abstract void registerProcessObserver(IProcessObserver processObserver);
|
||||
|
||||
/**
|
||||
* Unregisters the specified {@code processObserver}.
|
||||
*/
|
||||
public abstract void unregisterProcessObserver(IProcessObserver processObserver);
|
||||
}
|
||||
|
||||
@@ -19,5 +19,6 @@ package android.app;
|
||||
/** {@hide} */
|
||||
oneway interface IProcessObserver {
|
||||
void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
|
||||
void onForegroundServicesChanged(int pid, int uid, int serviceTypes);
|
||||
void onProcessDied(int pid, int uid);
|
||||
}
|
||||
|
||||
@@ -1273,11 +1273,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
|
||||
static final class ProcessChangeItem {
|
||||
static final int CHANGE_ACTIVITIES = 1<<0;
|
||||
static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
|
||||
int changes;
|
||||
int uid;
|
||||
int pid;
|
||||
int processState;
|
||||
boolean foregroundActivities;
|
||||
int foregroundServiceTypes;
|
||||
}
|
||||
|
||||
static final class UidObserverRegistration {
|
||||
@@ -3079,6 +3081,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
observer.onForegroundActivitiesChanged(item.pid, item.uid,
|
||||
item.foregroundActivities);
|
||||
}
|
||||
if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) {
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid="
|
||||
+ item.uid + ": " + item.foregroundServiceTypes);
|
||||
observer.onForegroundServicesChanged(item.pid, item.uid,
|
||||
item.foregroundServiceTypes);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
@@ -3093,6 +3102,47 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("this")
|
||||
ProcessChangeItem enqueueProcessChangeItemLocked(int uid, int pid) {
|
||||
int i = mPendingProcessChanges.size()-1;
|
||||
ActivityManagerService.ProcessChangeItem item = null;
|
||||
while (i >= 0) {
|
||||
item = mPendingProcessChanges.get(i);
|
||||
if (item.pid == pid) {
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Re-using existing item: " + item);
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
// No existing item in pending changes; need a new one.
|
||||
final int NA = mAvailProcessChanges.size();
|
||||
if (NA > 0) {
|
||||
item = mAvailProcessChanges.remove(NA-1);
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Retrieving available item: " + item);
|
||||
} else {
|
||||
item = new ActivityManagerService.ProcessChangeItem();
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Allocating new item: " + item);
|
||||
}
|
||||
item.changes = 0;
|
||||
item.pid = pid;
|
||||
item.uid = uid;
|
||||
if (mPendingProcessChanges.size() == 0) {
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"*** Enqueueing dispatch processes changed!");
|
||||
mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
|
||||
.sendToTarget();
|
||||
}
|
||||
mPendingProcessChanges.add(item);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void dispatchProcessDied(int pid, int uid) {
|
||||
int i = mProcessObservers.beginBroadcast();
|
||||
while (i > 0) {
|
||||
@@ -16275,11 +16325,12 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
@GuardedBy("this")
|
||||
final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
|
||||
int fgServiceTypes, boolean oomAdj) {
|
||||
proc.setHasForegroundServices(isForeground, fgServiceTypes);
|
||||
|
||||
final boolean hasFgServiceLocationType =
|
||||
(fgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
|
||||
if (isForeground != proc.hasForegroundServices()
|
||||
|| proc.hasLocationForegroundServices() != hasFgServiceLocationType) {
|
||||
proc.setHasForegroundServices(isForeground, fgServiceTypes);
|
||||
ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
|
||||
proc.info.uid);
|
||||
if (isForeground) {
|
||||
@@ -16308,6 +16359,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
updateOomAdjLocked();
|
||||
}
|
||||
}
|
||||
|
||||
if (proc.getForegroundServiceTypes() != fgServiceTypes) {
|
||||
proc.setReportedForegroundServiceTypes(fgServiceTypes);
|
||||
ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.info.uid, proc.pid);
|
||||
item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
|
||||
item.foregroundServiceTypes = fgServiceTypes;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
|
||||
@@ -18101,6 +18159,34 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
public void prepareForPossibleShutdown() {
|
||||
ActivityManagerService.this.prepareForPossibleShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRunningForegroundService(int uid, int foregroundServicetype) {
|
||||
synchronized (ActivityManagerService.this) {
|
||||
for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
|
||||
final ProcessRecord pr = mProcessList.mLruProcesses.get(i);
|
||||
if (pr.uid != uid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pr.getForegroundServiceTypes() & foregroundServicetype) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerProcessObserver(IProcessObserver processObserver) {
|
||||
ActivityManagerService.this.registerProcessObserver(processObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterProcessObserver(IProcessObserver processObserver) {
|
||||
ActivityManagerService.this.unregisterProcessObserver(processObserver);
|
||||
}
|
||||
}
|
||||
|
||||
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
|
||||
|
||||
@@ -38,7 +38,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
|
||||
import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
|
||||
import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
|
||||
import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
|
||||
import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
|
||||
import static com.android.server.am.ActivityManagerService.TAG_LRU;
|
||||
@@ -1921,41 +1920,9 @@ public final class OomAdjuster {
|
||||
if (changes != 0) {
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Changes in " + app + ": " + changes);
|
||||
int i = mService.mPendingProcessChanges.size()-1;
|
||||
ActivityManagerService.ProcessChangeItem item = null;
|
||||
while (i >= 0) {
|
||||
item = mService.mPendingProcessChanges.get(i);
|
||||
if (item.pid == app.pid) {
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Re-using existing item: " + item);
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
if (i < 0) {
|
||||
// No existing item in pending changes; need a new one.
|
||||
final int NA = mService.mAvailProcessChanges.size();
|
||||
if (NA > 0) {
|
||||
item = mService.mAvailProcessChanges.remove(NA-1);
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Retrieving available item: " + item);
|
||||
} else {
|
||||
item = new ActivityManagerService.ProcessChangeItem();
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Allocating new item: " + item);
|
||||
}
|
||||
item.changes = 0;
|
||||
item.pid = app.pid;
|
||||
item.uid = app.info.uid;
|
||||
if (mService.mPendingProcessChanges.size() == 0) {
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"*** Enqueueing dispatch processes changed!");
|
||||
mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
|
||||
.sendToTarget();
|
||||
}
|
||||
mService.mPendingProcessChanges.add(item);
|
||||
}
|
||||
item.changes |= changes;
|
||||
ActivityManagerService.ProcessChangeItem item =
|
||||
mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
|
||||
item.changes = changes;
|
||||
item.foregroundActivities = app.repForegroundActivities;
|
||||
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
|
||||
"Item " + Integer.toHexString(System.identityHashCode(item))
|
||||
|
||||
@@ -174,6 +174,7 @@ class ProcessRecord implements WindowProcessListener {
|
||||
boolean hasStartedServices; // Are there any started services running in this process?
|
||||
private boolean mHasForegroundServices; // Running any services that are foreground?
|
||||
private int mFgServiceTypes; // Type of foreground service, if there is a foreground service.
|
||||
private int mRepFgServiceTypes; // Last reported foreground service types.
|
||||
private boolean mHasForegroundActivities; // Running any activities that are foreground?
|
||||
boolean repForegroundActivities; // Last reported foreground activities.
|
||||
boolean systemNoUi; // This is a system process, but not currently showing UI.
|
||||
@@ -1079,6 +1080,18 @@ class ProcessRecord implements WindowProcessListener {
|
||||
&& (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
|
||||
}
|
||||
|
||||
int getForegroundServiceTypes() {
|
||||
return mHasForegroundServices ? mFgServiceTypes : 0;
|
||||
}
|
||||
|
||||
int getReportedForegroundServiceTypes() {
|
||||
return mRepFgServiceTypes;
|
||||
}
|
||||
|
||||
void setReportedForegroundServiceTypes(int foregroundServiceTypes) {
|
||||
mRepFgServiceTypes = foregroundServiceTypes;
|
||||
}
|
||||
|
||||
void setHasForegroundActivities(boolean hasForegroundActivities) {
|
||||
mHasForegroundActivities = hasForegroundActivities;
|
||||
mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
|
||||
|
||||
@@ -17,9 +17,14 @@
|
||||
package com.android.server.media.projection;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.IProcessObserver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.media.MediaRouter;
|
||||
import android.media.projection.IMediaProjection;
|
||||
@@ -29,6 +34,8 @@ import android.media.projection.IMediaProjectionWatcherCallback;
|
||||
import android.media.projection.MediaProjectionInfo;
|
||||
import android.media.projection.MediaProjectionManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
@@ -38,6 +45,7 @@ import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.Watchdog;
|
||||
|
||||
@@ -63,6 +71,8 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
|
||||
private final Context mContext;
|
||||
private final AppOpsManager mAppOps;
|
||||
private final ActivityManagerInternal mActivityManagerInternal;
|
||||
private final PackageManager mPackageManager;
|
||||
|
||||
private final MediaRouter mMediaRouter;
|
||||
private final MediaRouterCallback mMediaRouterCallback;
|
||||
@@ -77,6 +87,8 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
|
||||
mCallbackDelegate = new CallbackDelegate();
|
||||
mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
|
||||
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
|
||||
mMediaRouterCallback = new MediaRouterCallback();
|
||||
Watchdog.getInstance().addMonitor(this);
|
||||
@@ -88,6 +100,21 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
false /*allowIsolated*/);
|
||||
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,
|
||||
MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
|
||||
mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {
|
||||
@Override
|
||||
public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
|
||||
MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,
|
||||
serviceTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProcessDied(int pid, int uid) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,6 +132,29 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
synchronized (mLock) { /* check for deadlock */ }
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the set of active foreground service types for a given {@code uid / pid} changes.
|
||||
* We will stop the active projection grant if its owner targets {@code Q} or higher and has no
|
||||
* started foreground services of type {@code FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.
|
||||
*/
|
||||
private void handleForegroundServicesChanged(int pid, int uid, int serviceTypes) {
|
||||
synchronized (mLock) {
|
||||
if (mProjectionGrant == null || mProjectionGrant.uid != uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mProjectionGrant.targetSdkVersion < VERSION_CODES.Q) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((serviceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
mProjectionGrant.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void startProjectionLocked(final MediaProjection projection) {
|
||||
if (mProjectionGrant != null) {
|
||||
mProjectionGrant.stop();
|
||||
@@ -229,10 +279,19 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
if (packageName == null || packageName.isEmpty()) {
|
||||
throw new IllegalArgumentException("package name must not be empty");
|
||||
}
|
||||
|
||||
long callingToken = Binder.clearCallingIdentity();
|
||||
|
||||
MediaProjection projection;
|
||||
try {
|
||||
projection = new MediaProjection(type, uid, packageName);
|
||||
ApplicationInfo ai;
|
||||
try {
|
||||
ai = mPackageManager.getApplicationInfo(packageName, 0);
|
||||
} catch (NameNotFoundException e) {
|
||||
throw new IllegalArgumentException("No package matching :" + packageName);
|
||||
}
|
||||
|
||||
projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion);
|
||||
if (isPermanentGrant) {
|
||||
mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,
|
||||
projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);
|
||||
@@ -334,17 +393,19 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
public final int uid;
|
||||
public final String packageName;
|
||||
public final UserHandle userHandle;
|
||||
public final int targetSdkVersion;
|
||||
|
||||
private IMediaProjectionCallback mCallback;
|
||||
private IBinder mToken;
|
||||
private IBinder.DeathRecipient mDeathEater;
|
||||
private int mType;
|
||||
|
||||
public MediaProjection(int type, int uid, String packageName) {
|
||||
MediaProjection(int type, int uid, String packageName, int targetSdkVersion) {
|
||||
mType = type;
|
||||
this.uid = uid;
|
||||
this.packageName = packageName;
|
||||
userHandle = new UserHandle(UserHandle.getUserId(uid));
|
||||
this.targetSdkVersion = targetSdkVersion;
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
@@ -400,6 +461,14 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
+ " attempted to start already started MediaProjection");
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetSdkVersion >= Build.VERSION_CODES.Q
|
||||
&& !mActivityManagerInternal.hasRunningForegroundService(
|
||||
uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
|
||||
throw new SecurityException("Media projections require a foreground service"
|
||||
+ " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
|
||||
}
|
||||
|
||||
mCallback = callback;
|
||||
registerCallback(mCallback);
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user