am 8e3f2954: Merge "Update power manager to track uid state like netstats." into mnc-dev

* commit '8e3f29540db56d02a45966344133d6144c81e7c5':
  Update power manager to track uid state like netstats.
This commit is contained in:
Dianne Hackborn
2015-05-19 16:53:24 +00:00
committed by Android Git Automerger
13 changed files with 476 additions and 130 deletions

View File

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

View File

@@ -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);
@@ -5077,6 +5093,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();

View File

@@ -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;
@@ -844,4 +847,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;
}

View File

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

View File

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

View File

@@ -133,6 +133,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)}.
*/

View File

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

View File

@@ -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" : "";

View File

@@ -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;
@@ -654,10 +655,15 @@ 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.
@@ -1022,6 +1028,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
@@ -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));
@@ -9874,7 +9993,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;
@@ -9909,6 +10027,7 @@ public final class ActivityManagerService extends ActivityManagerNative
&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
r.persistent = true;
}
addProcessNameLocked(r);
return r;
}
@@ -9923,10 +10042,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();
}
@@ -10602,6 +10717,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();
@@ -12920,6 +13050,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();
@@ -15162,7 +15306,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.
@@ -15173,8 +15317,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));
@@ -15206,7 +15349,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) {
@@ -18289,7 +18432,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,
@@ -18301,7 +18444,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);
}
@@ -18320,6 +18463,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())
@@ -18463,6 +18631,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;
@@ -18610,6 +18786,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
@@ -18805,6 +18987,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() {

View File

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

View File

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

View File

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

View File

@@ -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;
}
}
@@ -2649,6 +2674,13 @@ public final class PowerManagerService extends SystemService
pw.println("Screen off timeout: " + screenOffTimeout + " ms");
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) {
@@ -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);
}
}
}