diff options
13 files changed, 476 insertions, 130 deletions
@@ -84,6 +84,7 @@ LOCAL_SRC_FILES += \ core/java/android/app/job/IJobScheduler.aidl \ core/java/android/app/job/IJobService.aidl \ core/java/android/app/ITransientNotification.aidl \ + core/java/android/app/IUidObserver.aidl \ core/java/android/app/IUiAutomationConnection.aidl \ core/java/android/app/IUiModeManager.aidl \ core/java/android/app/IUserSwitchObserver.aidl \ diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 1e9bc54..c83a45b 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1970,6 +1970,22 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case REGISTER_UID_OBSERVER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IUidObserver observer = IUidObserver.Stub.asInterface( + data.readStrongBinder()); + registerUidObserver(observer); + return true; + } + + case UNREGISTER_UID_OBSERVER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IUidObserver observer = IUidObserver.Stub.asInterface( + data.readStrongBinder()); + unregisterUidObserver(observer); + return true; + } + case GET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); @@ -5084,6 +5100,28 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public void registerUidObserver(IUidObserver observer) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(observer != null ? observer.asBinder() : null); + mRemote.transact(REGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + public void unregisterUidObserver(IUidObserver observer) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(observer != null ? observer.asBinder() : null); + mRemote.transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 05a936c..a7c5cb9 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -387,6 +387,9 @@ public interface IActivityManager extends IInterface { public void registerProcessObserver(IProcessObserver observer) throws RemoteException; public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException; + public void registerUidObserver(IUidObserver observer) throws RemoteException; + public void unregisterUidObserver(IUidObserver observer) throws RemoteException; + public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException; public boolean isIntentSenderAnActivity(IIntentSender sender) throws RemoteException; @@ -846,4 +849,6 @@ public interface IActivityManager extends IInterface { int UPDATE_DEVICE_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+295; int UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296; int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297; + int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298; + int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+299; } diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl new file mode 100644 index 0000000..308cb94 --- /dev/null +++ b/core/java/android/app/IUidObserver.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +/** {@hide} */ +oneway interface IUidObserver { + void onUidStateChanged(int uid, int procState); + void onUidGone(int uid); +} diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index 9a0d0d0..e523285 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -136,4 +136,8 @@ public abstract class PowerManagerInternal { public abstract void setDeviceIdleMode(boolean enabled); public abstract void setDeviceIdleWhitelist(int[] appids); + + public abstract void updateUidProcState(int uid, int procState); + + public abstract void uidGone(int uid); } diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 92e874f..dc965ed 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -134,6 +134,24 @@ public class SparseArray<E> implements Cloneable { } /** + * @hide + * Removes the mapping from the specified key, if there was any, returning the old value. + */ + public E removeReturnOld(int key) { + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); + + if (i >= 0) { + if (mValues[i] != DELETED) { + final E old = (E) mValues[i]; + mValues[i] = DELETED; + mGarbage = true; + return old; + } + } + return null; + } + + /** * Alias for {@link #delete(int)}. */ public void remove(int key) { diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java index 6ff0304..23a8bd7 100644 --- a/core/java/com/android/internal/app/ProcessMap.java +++ b/core/java/com/android/internal/app/ProcessMap.java @@ -39,14 +39,16 @@ public class ProcessMap<E> { return value; } - public void remove(String name, int uid) { + public E remove(String name, int uid) { SparseArray<E> uids = mMap.get(name); if (uids != null) { - uids.remove(uid); + final E old = uids.removeReturnOld(uid); if (uids.size() == 0) { mMap.remove(name); } + return old; } + return null; } public ArrayMap<String, SparseArray<E>> getMap() { diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java index 925fae0..ec2bd67 100644 --- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -71,6 +71,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_TASKS = DEBUG_ALL || false; static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false; static final boolean DEBUG_TRANSITION = DEBUG_ALL || false; + static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false; static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false; static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false; static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false; @@ -104,6 +105,8 @@ class ActivityManagerDebugConfig { static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : ""; static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : ""; static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : ""; + static final String POSTFIX_UID_OBSERVERS = (APPEND_CATEGORY_NAME) + ? "_UidObservers" : ""; static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : ""; static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : ""; static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : ""; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a8ab667..caa4058 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -129,6 +129,7 @@ import android.app.INotificationManager; import android.app.IProcessObserver; import android.app.IServiceConnection; import android.app.IStopUserCallback; +import android.app.IUidObserver; import android.app.IUiAutomationConnection; import android.app.IUserSwitchObserver; import android.app.Instrumentation; @@ -253,7 +254,6 @@ import java.util.concurrent.atomic.AtomicLong; public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { - private static final String USER_DATA_DIR = "/data/user/"; // File that stores last updated system version and called preboot receivers static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat"; @@ -278,6 +278,7 @@ public final class ActivityManagerService extends ActivityManagerNative private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE; private static final String TAG_STACK = TAG + POSTFIX_STACK; private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; + private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS; private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION; private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; @@ -655,9 +656,14 @@ public final class ActivityManagerService extends ActivityManagerNative long mPreviousProcessVisibleTime; /** + * Track all uids that have actively running processes. + */ + final SparseArray<UidRecord> mActiveUids = new SparseArray<>(); + + /** * Which uses have been started, so are allowed to run code. */ - final SparseArray<UserStartedState> mStartedUsers = new SparseArray<UserStartedState>(); + final SparseArray<UserStartedState> mStartedUsers = new SparseArray<>(); /** * LRU list of history of current users. Most recently current is at the end. @@ -1023,6 +1029,11 @@ public final class ActivityManagerService extends ActivityManagerNative private IVoiceInteractionSession mRunningVoice; /** + * For some direct access we need to power manager. + */ + PowerManagerInternal mLocalPowerManager; + + /** * We want to hold a wake lock while running a voice interaction session, since * this may happen with the screen off and we need to keep the CPU running to * be able to continue to interact with the user. @@ -1174,7 +1185,7 @@ public final class ActivityManagerService extends ActivityManagerNative final long[] mTmpLong = new long[1]; - static class ProcessChangeItem { + static final class ProcessChangeItem { static final int CHANGE_ACTIVITIES = 1<<0; static final int CHANGE_PROCESS_STATE = 1<<1; int changes; @@ -1184,14 +1195,17 @@ public final class ActivityManagerService extends ActivityManagerNative boolean foregroundActivities; } - final RemoteCallbackList<IProcessObserver> mProcessObservers - = new RemoteCallbackList<IProcessObserver>(); + final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>(); ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; - final ArrayList<ProcessChangeItem> mPendingProcessChanges - = new ArrayList<ProcessChangeItem>(); - final ArrayList<ProcessChangeItem> mAvailProcessChanges - = new ArrayList<ProcessChangeItem>(); + final ArrayList<ProcessChangeItem> mPendingProcessChanges = new ArrayList<>(); + final ArrayList<ProcessChangeItem> mAvailProcessChanges = new ArrayList<>(); + + final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>(); + UidRecord.ChangeItem[] mActiveUidChanges = new UidRecord.ChangeItem[5]; + + final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>(); + final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>(); /** * Runtime CPU use collection thread. This object's lock is used to @@ -1316,6 +1330,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51; static final int DELETE_DUMPHEAP_MSG = 52; static final int FOREGROUND_PROFILE_CHANGED_MSG = 53; + static final int DISPATCH_UIDS_CHANGED = 54; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1538,6 +1553,19 @@ public final class ActivityManagerService extends ActivityManagerNative d.dismiss(); break; } + case DISPATCH_PROCESSES_CHANGED: { + dispatchProcessesChanged(); + break; + } + case DISPATCH_PROCESS_DIED: { + final int pid = msg.arg1; + final int uid = msg.arg2; + dispatchProcessDied(pid, uid); + break; + } + case DISPATCH_UIDS_CHANGED: { + dispatchUidsChanged(); + } break; } } } @@ -1723,16 +1751,6 @@ public final class ActivityManagerService extends ActivityManagerNative sendMessageDelayed(nmsg, POWER_CHECK_DELAY); } } break; - case DISPATCH_PROCESSES_CHANGED: { - dispatchProcessesChanged(); - break; - } - case DISPATCH_PROCESS_DIED: { - final int pid = msg.arg1; - final int uid = msg.arg2; - dispatchProcessDied(pid, uid); - break; - } case REPORT_MEM_USAGE_MSG: { final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj; Thread thread = new Thread() { @@ -2091,7 +2109,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.pid = MY_PID; app.maxAdj = ProcessList.SYSTEM_ADJ; app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); - mProcessNames.put(app.processName, app.uid, app); synchronized (mPidsSelfLocked) { mPidsSelfLocked.put(app.pid, app); } @@ -2343,6 +2360,7 @@ public final class ActivityManagerService extends ActivityManagerNative public void initPowerManagement() { mStackSupervisor.initPowerManagement(); mBatteryStatsService.initPowerManagement(); + mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class); PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*"); mVoiceWakeLock.setReferenceCounted(false); @@ -3073,10 +3091,6 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } app.crashHandler = crashHandler; - mProcessNames.put(processName, app.uid, app); - if (isolated) { - mIsolatedProcesses.put(app.uid, app); - } checkTime(startTime, "startProcess: done creating new process record"); } else { // If this is a new package in the process, add the package to the list @@ -3562,7 +3576,6 @@ public final class ActivityManagerService extends ActivityManagerNative mActiveProcessChanges = new ProcessChangeItem[N]; } mPendingProcessChanges.toArray(mActiveProcessChanges); - mAvailProcessChanges.addAll(mPendingProcessChanges); mPendingProcessChanges.clear(); if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, "*** Delivering " + N + " process changes"); @@ -3595,6 +3608,12 @@ public final class ActivityManagerService extends ActivityManagerNative } } mProcessObservers.finishBroadcast(); + + synchronized (this) { + for (int j=0; j<N; j++) { + mAvailProcessChanges.add(mActiveProcessChanges[j]); + } + } } private void dispatchProcessDied(int pid, int uid) { @@ -3612,6 +3631,67 @@ public final class ActivityManagerService extends ActivityManagerNative mProcessObservers.finishBroadcast(); } + private void dispatchUidsChanged() { + int N; + synchronized (this) { + N = mPendingUidChanges.size(); + if (mActiveUidChanges.length < N) { + mActiveUidChanges = new UidRecord.ChangeItem[N]; + } + for (int i=0; i<N; i++) { + final UidRecord.ChangeItem change = mPendingUidChanges.get(i); + mActiveUidChanges[i] = change; + change.uidRecord.pendingChange = null; + change.uidRecord = null; + } + mPendingUidChanges.clear(); + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "*** Delivering " + N + " uid changes"); + } + + if (mLocalPowerManager != null) { + for (int j=0; j<N; j++) { + UidRecord.ChangeItem item = mActiveUidChanges[j]; + if (item.gone) { + mLocalPowerManager.uidGone(item.uid); + } else { + mLocalPowerManager.updateUidProcState(item.uid, item.processState); + } + } + } + + int i = mUidObservers.beginBroadcast(); + while (i > 0) { + i--; + final IUidObserver observer = mUidObservers.getBroadcastItem(i); + if (observer != null) { + try { + for (int j=0; j<N; j++) { + UidRecord.ChangeItem item = mActiveUidChanges[j]; + if (item.gone) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID gone uid=" + item.uid); + observer.onUidGone(item.uid); + } else { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID CHANGED uid=" + item.uid + + ": " + item.processState); + observer.onUidStateChanged(item.uid, item.processState); + } + } + } catch (RemoteException e) { + } + } + } + mUidObservers.finishBroadcast(); + + synchronized (this) { + for (int j=0; j<N; j++) { + mAvailUidChanges.add(mActiveUidChanges[j]); + } + } + } + @Override public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, @@ -5623,6 +5703,47 @@ public final class ActivityManagerService extends ActivityManagerNative return didSomething; } + private final ProcessRecord removeProcessNameLocked(final String name, final int uid) { + ProcessRecord old = mProcessNames.remove(name, uid); + if (old != null) { + old.uidRecord.numProcs--; + if (old.uidRecord.numProcs == 0) { + // No more processes using this uid, tell clients it is gone. + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "No more processes in " + old.uidRecord); + enqueueUidChangeLocked(old.uidRecord, true); + mActiveUids.remove(uid); + } + old.uidRecord = null; + } + mIsolatedProcesses.remove(uid); + return old; + } + + private final void addProcessNameLocked(ProcessRecord proc) { + // We shouldn't already have a process under this name, but just in case we + // need to clean up whatever may be there now. + ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid); + if (old != null) { + Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc); + } + UidRecord uidRec = mActiveUids.get(proc.uid); + if (uidRec == null) { + uidRec = new UidRecord(proc.uid); + // This is the first appearance of the uid, report it now! + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "Creating new process uid: " + uidRec); + mActiveUids.put(proc.uid, uidRec); + enqueueUidChangeLocked(uidRec, false); + } + proc.uidRecord = uidRec; + uidRec.numProcs++; + mProcessNames.put(proc.processName, proc.uid, proc); + if (proc.isolated) { + mIsolatedProcesses.put(proc.uid, proc); + } + } + private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart, boolean allowRestart, String reason) { final String name = app.processName; @@ -5630,8 +5751,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES, "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")"); - mProcessNames.remove(name, uid); - mIsolatedProcesses.remove(app.uid); + removeProcessNameLocked(name, uid); if (mHeavyWeightProcess == app) { mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG, mHeavyWeightProcess.userId, 0)); @@ -5684,8 +5804,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "Process " + app + " failed to attach"); EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId, pid, app.uid, app.processName); - mProcessNames.remove(app.processName, app.uid); - mIsolatedProcesses.remove(app.uid); + removeProcessNameLocked(app.processName, app.uid); if (mHeavyWeightProcess == app) { mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG, mHeavyWeightProcess.userId, 0)); @@ -9885,7 +10004,6 @@ public final class ActivityManagerService extends ActivityManagerNative final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, boolean isolated, int isolatedUid) { String proc = customProcess != null ? customProcess : info.processName; - BatteryStatsImpl.Uid.Proc ps = null; BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); final int userId = UserHandle.getUserId(info.uid); int uid = info.uid; @@ -9920,6 +10038,7 @@ public final class ActivityManagerService extends ActivityManagerNative && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { r.persistent = true; } + addProcessNameLocked(r); return r; } @@ -9934,10 +10053,6 @@ public final class ActivityManagerService extends ActivityManagerNative if (app == null) { app = newProcessRecordLocked(info, null, isolated, 0); - mProcessNames.put(info.processName, app.uid, app); - if (isolated) { - mIsolatedProcesses.put(app.uid, app); - } updateLruProcessLocked(app, false, null); updateOomAdjLocked(); } @@ -10613,6 +10728,21 @@ public final class ActivityManagerService extends ActivityManagerNative } } + public void registerUidObserver(IUidObserver observer) { + enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, + "registerUidObserver()"); + synchronized (this) { + mUidObservers.register(observer); + } + } + + @Override + public void unregisterUidObserver(IUidObserver observer) { + synchronized (this) { + mUidObservers.unregister(observer); + } + } + @Override public boolean convertFromTranslucent(IBinder token) { final long origId = Binder.clearCallingIdentity(); @@ -12932,6 +13062,20 @@ public final class ActivityManagerService extends ActivityManagerNative } } + if (mActiveUids.size() > 0) { + if (needSep) { + pw.println(); + } + pw.println(" UID states:"); + for (int i=0; i<mActiveUids.size(); i++) { + UidRecord uidRec = mActiveUids.valueAt(i); + pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid); + pw.print(": "); pw.println(uidRec); + } + needSep = true; + printedAnything = true; + } + if (mLruProcesses.size() > 0) { if (needSep) { pw.println(); @@ -15174,7 +15318,7 @@ public final class ActivityManagerService extends ActivityManagerNative mAvailProcessChanges.add(item); } } - mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget(); + mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget(); // If the caller is restarting this app, then leave it in its // current lists and let the caller take care of it. @@ -15185,8 +15329,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (!app.persistent || app.isolated) { if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Removing non-persistent process during cleanup: " + app); - mProcessNames.remove(app.processName, app.uid); - mIsolatedProcesses.remove(app.uid); + removeProcessNameLocked(app.processName, app.uid); if (mHeavyWeightProcess == app) { mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG, mHeavyWeightProcess.userId, 0)); @@ -15218,7 +15361,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (index < 0) { ProcessList.remove(app.pid); } - mProcessNames.put(app.processName, app.uid, app); + addProcessNameLocked(app); startProcessLocked(app, "restart", app.processName); return true; } else if (app.pid > 0 && app.pid != MY_PID) { @@ -18310,7 +18453,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (NA > 0) { item = mAvailProcessChanges.remove(NA-1); if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, - "Retreiving available item: " + item); + "Retrieving available item: " + item); } else { item = new ProcessChangeItem(); if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, @@ -18322,7 +18465,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mPendingProcessChanges.size() == 0) { if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, "*** Enqueueing dispatch processes changed!"); - mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget(); + mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget(); } mPendingProcessChanges.add(item); } @@ -18341,6 +18484,31 @@ public final class ActivityManagerService extends ActivityManagerNative return success; } + private final void enqueueUidChangeLocked(UidRecord uidRec, boolean gone) { + if (uidRec.pendingChange == null) { + if (mPendingUidChanges.size() == 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "*** Enqueueing dispatch uid changed!"); + mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED).sendToTarget(); + } + final int NA = mAvailUidChanges.size(); + if (NA > 0) { + uidRec.pendingChange = mAvailUidChanges.remove(NA-1); + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "Retrieving available item: " + uidRec.pendingChange); + } else { + uidRec.pendingChange = new UidRecord.ChangeItem(); + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "Allocating new item: " + uidRec.pendingChange); + } + uidRec.pendingChange.uidRecord = uidRec; + uidRec.pendingChange.uid = uidRec.uid; + mPendingUidChanges.add(uidRec.pendingChange); + } + uidRec.pendingChange.gone = gone; + uidRec.pendingChange.processState = uidRec.setProcState; + } + private void maybeUpdateUsageStats(ProcessRecord app) { if (DEBUG_USAGE_STATS) { Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList()) @@ -18484,6 +18652,14 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e); } + // Reset state in all uid records. + for (int i=mActiveUids.size()-1; i>=0; i--) { + final UidRecord uidRec = mActiveUids.valueAt(i); + if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "Starting update of " + uidRec); + uidRec.reset(); + } + mAdjSeq++; mNewNumServiceProcs = 0; mNewNumAServiceProcs = 0; @@ -18631,6 +18807,12 @@ public final class ActivityManagerService extends ActivityManagerNative // good to avoid having whatever code was running in them // left sitting around after no longer needed. app.kill("isolated not needed", true); + } else { + // Keeping this process, update its uid. + final UidRecord uidRec = app.uidRecord; + if (uidRec != null && uidRec.curProcState > app.curProcState) { + uidRec.curProcState = app.curProcState; + } } if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME @@ -18826,6 +19008,18 @@ public final class ActivityManagerService extends ActivityManagerNative requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered()); } + // Update from any uid changes. + for (int i=mActiveUids.size()-1; i>=0; i--) { + final UidRecord uidRec = mActiveUids.valueAt(i); + if (uidRec.setProcState != uidRec.curProcState) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "Changes in " + uidRec + ": proc state from " + uidRec.setProcState + + " to " + uidRec.curProcState); + uidRec.setProcState = uidRec.curProcState; + enqueueUidChangeLocked(uidRec, false); + } + } + if (mProcessStats.shouldWriteNowLocked(now)) { mHandler.post(new Runnable() { @Override public void run() { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 29e14f8..14759c3 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -62,8 +62,8 @@ final class ProcessRecord { final int userId; // user of process. final String processName; // name of the process // List of packages running in the process - final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList - = new ArrayMap<String, ProcessStats.ProcessStateHolder>(); + final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList = new ArrayMap<>(); + UidRecord uidRecord; // overall state of process's uid. ArraySet<String> pkgDeps; // additional packages we have a dependency on IApplicationThread thread; // the actual proc... may be null only if // 'persistent' is true (in which case we @@ -142,24 +142,20 @@ final class ProcessRecord { Object adjTarget; // Debugging: target component impacting oom_adj. Runnable crashHandler; // Optional local handler to be invoked in the process crash. - // contains HistoryRecord objects - final ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); + // all activities running in the process + final ArrayList<ActivityRecord> activities = new ArrayList<>(); // all ServiceRecord running in this process - final ArraySet<ServiceRecord> services = new ArraySet<ServiceRecord>(); + final ArraySet<ServiceRecord> services = new ArraySet<>(); // services that are currently executing code (need to remain foreground). - final ArraySet<ServiceRecord> executingServices - = new ArraySet<ServiceRecord>(); + final ArraySet<ServiceRecord> executingServices = new ArraySet<>(); // All ConnectionRecord this process holds - final ArraySet<ConnectionRecord> connections - = new ArraySet<ConnectionRecord>(); + final ArraySet<ConnectionRecord> connections = new ArraySet<>(); // all IIntentReceivers that are registered from this process. - final ArraySet<ReceiverList> receivers = new ArraySet<ReceiverList>(); + final ArraySet<ReceiverList> receivers = new ArraySet<>(); // class (String) -> ContentProviderRecord - final ArrayMap<String, ContentProviderRecord> pubProviders - = new ArrayMap<String, ContentProviderRecord>(); + final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>(); // All ContentProviderRecord process is using - final ArrayList<ContentProviderConnection> conProviders - = new ArrayList<ContentProviderConnection>(); + final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>(); boolean execServicesFg; // do we need to be executing services in the foreground? boolean persistent; // always keep this application running? diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java new file mode 100644 index 0000000..b4efbf0 --- /dev/null +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.app.ActivityManager; +import android.os.UserHandle; + +/** + * Overall information about a uid that has actively running processes. + */ +public final class UidRecord { + final int uid; + int curProcState; + int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; + int numProcs; + + static final class ChangeItem { + UidRecord uidRecord; + int uid; + boolean gone; + int processState; + } + + ChangeItem pendingChange; + + public UidRecord(int _uid) { + uid = _uid; + reset(); + } + + public void reset() { + curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("UidRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + UserHandle.formatUid(sb, uid); + sb.append(' '); + sb.append(ProcessList.makeProcStateString(curProcState)); + sb.append(" / "); + sb.append(numProcs); + sb.append(" procs}"); + return sb.toString(); + } +} diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 24ab3b8..1a79568 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -81,6 +81,7 @@ import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.IProcessObserver; +import android.app.IUidObserver; import android.app.Notification; import android.app.PendingIntent; import android.app.usage.UsageStatsManagerInternal; @@ -153,10 +154,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.AppOpsService; import com.android.server.DeviceIdleController; import com.android.server.LocalServices; -import com.android.server.SystemConfig; import com.google.android.collect.Lists; import org.xmlpull.v1.XmlPullParser; @@ -294,9 +293,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub /** Set of currently active {@link Notification} tags. */ private final ArraySet<String> mActiveNotifs = new ArraySet<String>(); - /** Foreground at both UID and PID granularity. */ + /** Foreground at UID granularity. */ final SparseIntArray mUidState = new SparseIntArray(); - final SparseArray<SparseIntArray> mUidPidState = new SparseArray<>(); /** The current maximum process state that we are considering to be foreground. */ private int mCurForegroundState = ActivityManager.PROCESS_STATE_TOP; @@ -411,7 +409,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub updateScreenOn(); try { - mActivityManager.registerProcessObserver(mProcessObserver); + mActivityManager.registerUidObserver(mUidObserver); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { // ignored; both services live in system_server @@ -477,40 +475,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub } - private IProcessObserver mProcessObserver = new IProcessObserver.Stub() { - @Override - public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { - } - - @Override - public void onProcessStateChanged(int pid, int uid, int procState) { + private IUidObserver mUidObserver = new IUidObserver.Stub() { + @Override public void onUidStateChanged(int uid, int procState) throws RemoteException { synchronized (mRulesLock) { - // because a uid can have multiple pids running inside, we need to - // remember all pid states and summarize foreground at uid level. - - // record foreground for this specific pid - SparseIntArray pidState = mUidPidState.get(uid); - if (pidState == null) { - pidState = new SparseIntArray(2); - mUidPidState.put(uid, pidState); - } - pidState.put(pid, procState); - computeUidStateLocked(uid); + updateUidStateLocked(uid, procState); } } - @Override - public void onProcessDied(int pid, int uid) { + @Override public void onUidGone(int uid) throws RemoteException { synchronized (mRulesLock) { - // clear records and recompute, when they exist - final SparseIntArray pidState = mUidPidState.get(uid); - if (pidState != null) { - pidState.delete(pid); - if (pidState.size() <= 0) { - mUidPidState.remove(uid); - } - computeUidStateLocked(uid); - } + removeUidStateLocked(uid); } } }; @@ -1919,14 +1893,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub fout.print(state); fout.print(state <= mCurForegroundState ? " (fg)" : " (bg)"); - fout.print(" pids="); - final int foregroundIndex = mUidPidState.indexOfKey(uid); - if (foregroundIndex < 0) { - fout.print("UNKNOWN"); - } else { - dumpSparseIntArray(fout, mUidPidState.valueAt(foregroundIndex)); - } - fout.print(" rules="); final int rulesIndex = mUidRules.indexOfKey(uid); if (rulesIndex < 0) { @@ -1957,36 +1923,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub } /** - * Process state of PID changed; recompute state at UID level. If - * changed, will trigger {@link #updateRulesForUidLocked(int)}. + * Process state of UID changed; if needed, will trigger + * {@link #updateRulesForUidLocked(int)}. */ - void computeUidStateLocked(int uid) { - final SparseIntArray pidState = mUidPidState.get(uid); - - // current pid is dropping foreground; examine other pids - int uidState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; - if (pidState != null) { - final int size = pidState.size(); - for (int i = 0; i < size; i++) { - final int state = pidState.valueAt(i); - if (state < uidState) { - uidState = state; - } - } - } - + void updateUidStateLocked(int uid, int uidState) { final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); if (oldUidState != uidState) { // state changed, push updated rules mUidState.put(uid, uidState); - final boolean oldForeground = oldUidState <= mCurForegroundState; - final boolean newForeground = uidState <= mCurForegroundState; - if (oldForeground != newForeground) { - updateRulesForUidLocked(uid); + updateRulesForUidStateChangeLocked(uid, oldUidState, uidState); + } + } + + void removeUidStateLocked(int uid) { + final int index = mUidState.indexOfKey(uid); + if (index >= 0) { + final int oldUidState = mUidState.valueAt(index); + mUidState.removeAt(index); + if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) { + updateRulesForUidStateChangeLocked(uid, oldUidState, + ActivityManager.PROCESS_STATE_CACHED_EMPTY); } } } + void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) { + final boolean oldForeground = oldUidState <= mCurForegroundState; + final boolean newForeground = newUidState <= mCurForegroundState; + if (oldForeground != newForeground) { + updateRulesForUidLocked(uid); + } + } + private void updateScreenOn() { synchronized (mRulesLock) { try { @@ -2381,16 +2349,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub } } - private static void dumpSparseIntArray(PrintWriter fout, SparseIntArray value) { - fout.print("["); - final int size = value.size(); - for (int i = 0; i < size; i++) { - fout.print(value.keyAt(i) + "=" + value.valueAt(i)); - if (i < size - 1) fout.print(","); - } - fout.print("]"); - } - @Override public void factoryReset(String subscriber) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 74df0a0..5aea746 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -16,6 +16,8 @@ package com.android.server.power; +import android.app.ActivityManager; +import android.util.SparseIntArray; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.internal.os.BackgroundThread; @@ -436,6 +438,8 @@ public final class PowerManagerService extends SystemService // Set of app ids that we will always respect the wake locks for. int[] mDeviceIdleWhitelist = new int[0]; + private final SparseIntArray mUidState = new SparseIntArray(); + // True if theater mode is enabled private boolean mTheaterModeEnabled; @@ -2316,6 +2320,24 @@ public final class PowerManagerService extends SystemService } } + void updateUidProcStateInternal(int uid, int procState) { + synchronized (mLock) { + mUidState.put(uid, procState); + if (mDeviceIdleMode) { + updateWakeLockDisabledStatesLocked(); + } + } + } + + void uidGoneInternal(int uid) { + synchronized (mLock) { + mUidState.delete(uid); + if (mDeviceIdleMode) { + updateWakeLockDisabledStatesLocked(); + } + } + } + private void updateWakeLockDisabledStatesLocked() { boolean changed = false; final int numWakeLocks = mWakeLocks.size(); @@ -2349,7 +2371,10 @@ public final class PowerManagerService extends SystemService // If we are in idle mode, we will ignore all partial wake locks that are // for application uids that are not whitelisted. if (appid >= Process.FIRST_APPLICATION_UID && - Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0) { + Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 && + mUidState.get(wakeLock.mOwnerUid, + ActivityManager.PROCESS_STATE_CACHED_EMPTY) + > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) { disabled = true; } } @@ -2650,6 +2675,13 @@ public final class PowerManagerService extends SystemService pw.println("Screen dim duration: " + screenDimDuration + " ms"); pw.println(); + pw.println("UID states:"); + for (int i=0; i<mUidState.size(); i++) { + pw.print(" UID "); UserHandle.formatUid(pw, mUidState.keyAt(i)); + pw.print(": "); pw.println(mUidState.valueAt(i)); + } + + pw.println(); pw.println("Wake Locks: size=" + mWakeLocks.size()); for (WakeLock wl : mWakeLocks) { pw.println(" " + wl); @@ -3451,5 +3483,15 @@ public final class PowerManagerService extends SystemService public void setDeviceIdleWhitelist(int[] appids) { setDeviceIdleWhitelistInternal(appids); } + + @Override + public void updateUidProcState(int uid, int procState) { + updateUidProcStateInternal(uid, procState); + } + + @Override + public void uidGone(int uid) { + uidGoneInternal(uid); + } } } |