Merge "Require a foreground service of a specific type to start media projection."

This commit is contained in:
Narayan Kamath
2019-03-20 10:18:05 +00:00
committed by Android (Google) Code Review
6 changed files with 192 additions and 39 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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))

View File

@@ -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);

View File

@@ -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 {