diff options
| author | 2019-03-20 10:18:05 +0000 | |
|---|---|---|
| committer | 2019-03-20 10:18:05 +0000 | |
| commit | 3f95d3bc249bfa3a547a5a35b35befefbc225e9b (patch) | |
| tree | 5181f155b7b04dfca8a3672dbef7325e53c972a4 | |
| parent | ce844797cdbcc54397836dbcac0ba9328a91ea35 (diff) | |
| parent | 396ce7296bba8d21037961625b41072cf20b61b8 (diff) | |
Merge "Require a foreground service of a specific type to start media projection."
6 files changed, 192 insertions, 39 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index f6cfe4855070..e8d32932503b 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -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); } diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl index b436aa2bcd0f..7be3620f317b 100644 --- a/core/java/android/app/IProcessObserver.aidl +++ b/core/java/android/app/IProcessObserver.aidl @@ -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); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 82254761817e..92b7c3c92faf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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) { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 9056f76c4086..aa03de1115b2 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -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)) diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 51b1ae197821..17b244c75819 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -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); 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 270fbc68e143..3872523492a7 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -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 { |