summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/app/ActivityManagerNative.java38
-rw-r--r--core/java/android/app/IActivityManager.java5
-rw-r--r--core/java/android/app/IUidObserver.aidl23
-rw-r--r--core/java/android/os/PowerManagerInternal.java4
-rw-r--r--core/java/android/util/SparseArray.java18
-rw-r--r--core/java/com/android/internal/app/ProcessMap.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java274
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java24
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java62
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java104
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java44
13 files changed, 476 insertions, 130 deletions
diff --git a/Android.mk b/Android.mk
index eb6e7b5..146afe0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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);
+ }
}
}