diff options
Diffstat (limited to 'services')
52 files changed, 1850 insertions, 958 deletions
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 32b91d2..f5d27f9 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -41,6 +41,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -52,6 +53,7 @@ import android.provider.Settings.SettingNotFoundException; import android.util.Log; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; @@ -1737,17 +1739,32 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); - writer.println("enabled: " + mEnable); - writer.println("state: " + mState); - writer.println("address: " + mAddress); - writer.println("name: " + mName); + writer.println("Bluetooth Status"); + writer.println(" enabled: " + mEnable); + writer.println(" state: " + mState); + writer.println(" address: " + mAddress); + writer.println(" name: " + mName + "\n"); + writer.flush(); + if (mBluetooth == null) { writer.println("Bluetooth Service not connected"); } else { + ParcelFileDescriptor pfd = null; try { - writer.println(mBluetooth.dump()); + pfd = ParcelFileDescriptor.dup(fd); + mBluetooth.dump(pfd); } catch (RemoteException re) { writer.println("RemoteException while calling Bluetooth Service"); + } catch (IOException ioe) { + writer.println("IOException attempting to dup() fd"); + } finally { + if (pfd != null) { + try { + pfd.close(); + } catch (IOException ioe) { + writer.println("IOException attempting to close() fd"); + } + } } } } diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index b7bc0f0..0b33812 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -142,6 +142,7 @@ public class DeviceIdleController extends SystemService { private PendingIntent mAlarmIntent; private Intent mIdleIntent; private Display mCurDisplay; + private boolean mIdleDisabled; private boolean mScreenOn; private boolean mCharging; private boolean mSigMotionActive; @@ -187,10 +188,16 @@ public class DeviceIdleController extends SystemService { private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>(); /** - * UIDs that have been white-listed to opt out of power save restrictions. + * App IDs that have been white-listed to opt out of power save restrictions. */ private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray(); + /** + * Current app IDs that are in the complete power save white list. This array can + * be shared with others because it will not be modified once set. + */ + private int[] mPowerSaveWhitelistAppIdArray = new int[0]; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { @@ -306,6 +313,10 @@ public class DeviceIdleController extends SystemService { return getAppIdWhitelistInternal(); } + @Override public boolean isPowerSaveWhitelistApp(String name) { + return isPowerSaveWhitelistAppInternal(name); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { DeviceIdleController.this.dump(fd, pw, args); } @@ -381,6 +392,8 @@ public class DeviceIdleController extends SystemService { filter.addAction(ACTION_STEP_IDLE_STATE); getContext().registerReceiver(mReceiver, filter); + mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray); + mDisplayManager.registerDisplayListener(mDisplayListener, null); updateDisplayLocked(); } @@ -443,14 +456,16 @@ public class DeviceIdleController extends SystemService { } } + public boolean isPowerSaveWhitelistAppInternal(String packageName) { + synchronized (this) { + return mPowerSaveWhitelistApps.containsKey(packageName) + || mPowerSaveWhitelistUserApps.containsKey(packageName); + } + } + public int[] getAppIdWhitelistInternal() { synchronized (this) { - int size = mPowerSaveWhitelistAppIds.size(); - int[] appids = new int[size]; - for (int i = 0; i < size; i++) { - appids[i] = mPowerSaveWhitelistAppIds.keyAt(i); - } - return appids; + return mPowerSaveWhitelistAppIdArray; } } @@ -499,7 +514,7 @@ public class DeviceIdleController extends SystemService { } void becomeInactiveIfAppropriateLocked() { - if (!mScreenOn && !mCharging && mState == STATE_ACTIVE) { + if (!mScreenOn && !mCharging && !mIdleDisabled && mState == STATE_ACTIVE) { // Screen has turned off; we are now going to become inactive and start // waiting to see if we will ultimately go idle. mState = STATE_INACTIVE; @@ -625,6 +640,15 @@ public class DeviceIdleController extends SystemService { for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) { mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true); } + int size = mPowerSaveWhitelistAppIds.size(); + int[] appids = new int[size]; + for (int i = 0; i < size; i++) { + appids[i] = mPowerSaveWhitelistAppIds.keyAt(i); + } + mPowerSaveWhitelistAppIdArray = appids; + if (mLocalPowerManager != null) { + mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray); + } } private void reportPowerSaveWhitelistChangedLocked() { @@ -763,6 +787,10 @@ public class DeviceIdleController extends SystemService { pw.println("Commands:"); pw.println(" step"); pw.println(" Immediately step to next state, without waiting for alarm."); + pw.println(" disable"); + pw.println(" Completely disable device idle mode."); + pw.println(" enable"); + pw.println(" Re-enable device idle mode after it had previously been disabled."); pw.println(" whitelist"); pw.println(" Add (prefix with +) or remove (prefix with -) packages."); } @@ -782,12 +810,32 @@ public class DeviceIdleController extends SystemService { if ("-h".equals(arg)) { dumpHelp(pw); return; + } else if ("-a".equals(arg)) { + // Ignore, we always dump all. } else if ("step".equals(arg)) { synchronized (this) { stepIdleStateLocked(); pw.print("Stepped to: "); pw.println(stateToString(mState)); } return; + } else if ("disable".equals(arg)) { + synchronized (this) { + if (!mIdleDisabled) { + mIdleDisabled = true; + becomeActiveLocked("disabled"); + pw.println("Idle mode disabled"); + } + } + return; + } else if ("enable".equals(arg)) { + synchronized (this) { + if (mIdleDisabled) { + mIdleDisabled = false; + becomeInactiveIfAppropriateLocked(); + pw.println("Idle mode enabled"); + } + } + return; } else if ("whitelist".equals(arg)) { i++; while (i < args.length) { @@ -853,6 +901,7 @@ public class DeviceIdleController extends SystemService { } pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor); pw.print(" mCurDisplay="); pw.println(mCurDisplay); + pw.print(" mIdleDisabled="); pw.println(mIdleDisabled); pw.print(" mScreenOn="); pw.println(mScreenOn); pw.print(" mCharging="); pw.println(mCharging); pw.print(" mSigMotionActive="); pw.println(mSigMotionActive); diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java index c79fdfc..3fdef1d 100644 --- a/services/core/java/com/android/server/GraphicsStatsService.java +++ b/services/core/java/com/android/server/GraphicsStatsService.java @@ -52,9 +52,9 @@ import java.util.ArrayList; * 2) ASHMEM_SIZE (for scratch space used during dumping) * 3) ASHMEM_SIZE * HISTORY_SIZE * - * Currently ASHMEM_SIZE is 256 bytes and HISTORY_SIZE is 10. Assuming + * Currently ASHMEM_SIZE is 256 bytes and HISTORY_SIZE is 20. Assuming * the system then also has 10 active rendering processes in the worst case - * this would end up using under 10KiB (8KiB for the buffers, plus some overhead + * this would end up using under 14KiB (12KiB for the buffers, plus some overhead * for userId, pid, package name, and a couple other objects) * * @hide */ @@ -63,7 +63,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { private static final String TAG = "GraphicsStatsService"; private static final int ASHMEM_SIZE = 256; - private static final int HISTORY_SIZE = 10; + private static final int HISTORY_SIZE = 20; private final Context mContext; private final Object mLock = new Object(); diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 9511f54..e856a93 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -1695,6 +1695,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub vis = 0; } mImeWindowVis = vis; + mInputShown = ((mImeWindowVis & InputMethodService.IME_VISIBLE) != 0); mBackDisposition = backDisposition; final boolean iconVisibility = ((vis & (InputMethodService.IME_ACTIVE)) != 0) && (mWindowManagerService.isHardKeyboardAvailable() diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 5df74c5..ed2de4a 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -356,28 +356,23 @@ public class LockSettingsService extends ILockSettings.Stub { return mStorage.hasPattern(userId); } - private void maybeUpdateKeystore(String password, int userHandle) { + private void setKeystorePassword(String password, int userHandle) { final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); final KeyStore ks = KeyStore.getInstance(); final List<UserInfo> profiles = um.getProfiles(userHandle); - boolean shouldReset = TextUtils.isEmpty(password); - - // For historical reasons, don't wipe a non-empty keystore if we have a single user with a - // single profile. - if (userHandle == UserHandle.USER_OWNER && profiles.size() == 1) { - if (!ks.isEmpty()) { - shouldReset = false; - } + for (UserInfo pi : profiles) { + ks.onUserPasswordChanged(pi.id, password); } + } + + private void unlockKeystore(String password, int userHandle) { + final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); + final KeyStore ks = KeyStore.getInstance(); + final List<UserInfo> profiles = um.getProfiles(userHandle); for (UserInfo pi : profiles) { - final int profileUid = UserHandle.getUid(pi.id, Process.SYSTEM_UID); - if (shouldReset) { - ks.resetUid(profileUid); - } else { - ks.passwordUid(password, profileUid); - } + ks.unlock(pi.id, password); } } @@ -423,7 +418,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (pattern == null) { getGateKeeperService().clearSecureUserId(userId); mStorage.writePatternHash(null, userId); - maybeUpdateKeystore(null, userId); + setKeystorePassword(null, userId); return; } @@ -451,7 +446,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (password == null) { getGateKeeperService().clearSecureUserId(userId); mStorage.writePasswordHash(null, userId); - maybeUpdateKeystore(null, userId); + setKeystorePassword(null, userId); return; } @@ -484,7 +479,7 @@ public class LockSettingsService extends ILockSettings.Stub { toEnrollBytes); if (hash != null) { - maybeUpdateKeystore(toEnroll, userId); + setKeystorePassword(toEnroll, userId); } return hash; @@ -530,7 +525,7 @@ public class LockSettingsService extends ILockSettings.Stub { byte[] hash = mLockPatternUtils.patternToHash( mLockPatternUtils.stringToPattern(pattern)); if (Arrays.equals(hash, storedHash.hash)) { - maybeUpdateKeystore(pattern, userId); + unlockKeystore(pattern, userId); // migrate password to GateKeeper setLockPattern(pattern, null, userId); if (!hasChallenge) { @@ -556,7 +551,7 @@ public class LockSettingsService extends ILockSettings.Stub { } // pattern has matched - maybeUpdateKeystore(pattern, userId); + unlockKeystore(pattern, userId); return token; } @@ -599,7 +594,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (storedHash.version == CredentialHash.VERSION_LEGACY) { byte[] hash = mLockPatternUtils.passwordToHash(password, userId); if (Arrays.equals(hash, storedHash.hash)) { - maybeUpdateKeystore(password, userId); + unlockKeystore(password, userId); // migrate password to GateKeeper setLockPassword(password, null, userId); if (!hasChallenge) { @@ -625,7 +620,7 @@ public class LockSettingsService extends ILockSettings.Stub { } // password has matched - maybeUpdateKeystore(password, userId); + unlockKeystore(password, userId); return token; } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 0925fa5..93ac51a 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -242,6 +242,7 @@ class MountService extends IMountService.Stub private static final int VERSION_INIT = 1; private static final int VERSION_ADD_PRIMARY = 2; + private static final int VERSION_FIX_PRIMARY = 3; private static final String TAG_VOLUMES = "volumes"; private static final String ATTR_VERSION = "version"; @@ -1187,8 +1188,17 @@ class MountService extends IMountService.Stub mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget(); } + private String getDefaultPrimaryStorageUuid() { + if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) { + return StorageManager.UUID_PRIMARY_PHYSICAL; + } else { + return StorageManager.UUID_PRIVATE_INTERNAL; + } + } + private void readSettingsLocked() { mRecords.clear(); + mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); FileInputStream fis = null; try { @@ -1202,16 +1212,13 @@ class MountService extends IMountService.Stub final String tag = in.getName(); if (TAG_VOLUMES.equals(tag)) { final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT); - if (version >= VERSION_ADD_PRIMARY) { + final boolean primaryPhysical = SystemProperties.getBoolean( + StorageManager.PROP_PRIMARY_PHYSICAL, false); + final boolean validAttr = (version >= VERSION_FIX_PRIMARY) + || (version >= VERSION_ADD_PRIMARY && !primaryPhysical); + if (validAttr) { mPrimaryStorageUuid = readStringAttribute(in, ATTR_PRIMARY_STORAGE_UUID); - } else { - if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, - false)) { - mPrimaryStorageUuid = StorageManager.UUID_PRIMARY_PHYSICAL; - } else { - mPrimaryStorageUuid = StorageManager.UUID_PRIVATE_INTERNAL; - } } } else if (TAG_VOLUME.equals(tag)) { @@ -1240,7 +1247,7 @@ class MountService extends IMountService.Stub out.setOutput(fos, "utf-8"); out.startDocument(null, true); out.startTag(null, TAG_VOLUMES); - writeIntAttribute(out, ATTR_VERSION, VERSION_ADD_PRIMARY); + writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY); writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid); final int size = mRecords.size(); for (int i = 0; i < size; i++) { @@ -1482,7 +1489,7 @@ class MountService extends IMountService.Stub // If this had been primary storage, revert back to internal and // reset vold so we bind into new volume into place. if (Objects.equals(mPrimaryStorageUuid, fsUuid)) { - mPrimaryStorageUuid = StorageManager.UUID_PRIVATE_INTERNAL; + mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); resetIfReadyAndConnected(); } @@ -1497,11 +1504,13 @@ class MountService extends IMountService.Stub final String fsUuid = mRecords.keyAt(i); mCallbacks.notifyVolumeForgotten(fsUuid); } - mRecords.clear(); - writeSettingsLocked(); - mPrimaryStorageUuid = StorageManager.UUID_PRIVATE_INTERNAL; + if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) { + mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); + } + + writeSettingsLocked(); resetIfReadyAndConnected(); } } @@ -1522,13 +1531,8 @@ class MountService extends IMountService.Stub waitForReady(); synchronized (mLock) { - final VolumeInfo from = Preconditions.checkNotNull( - findStorageForUuid(mPrimaryStorageUuid)); - final VolumeInfo to = Preconditions.checkNotNull( - findStorageForUuid(volumeUuid)); - - if (Objects.equals(from, to)) { - throw new IllegalArgumentException("Primary storage already at " + from); + if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) { + throw new IllegalArgumentException("Primary storage already at " + volumeUuid); } if (mMoveCallback != null) { @@ -1537,10 +1541,26 @@ class MountService extends IMountService.Stub mMoveCallback = callback; mMoveTargetUuid = volumeUuid; - try { - mConnector.execute("volume", "move_storage", from.id, to.id); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); + // When moving to/from primary physical volume, we probably just nuked + // the current storage location, so we have nothing to move. + if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid) + || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { + Slog.d(TAG, "Skipping move to/from primary physical"); + onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED); + onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED); + resetIfReadyAndConnected(); + + } else { + final VolumeInfo from = Preconditions.checkNotNull( + findStorageForUuid(mPrimaryStorageUuid)); + final VolumeInfo to = Preconditions.checkNotNull( + findStorageForUuid(volumeUuid)); + + try { + mConnector.execute("volume", "move_storage", from.id, to.id); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } } } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 3dece49..fa4d204 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import android.app.ActivityThread; import android.os.Build; @@ -119,14 +120,13 @@ public final class ActiveServices { // at the same time. final int mMaxStartingBackground; - final SparseArray<ServiceMap> mServiceMap = new SparseArray<ServiceMap>(); + final SparseArray<ServiceMap> mServiceMap = new SparseArray<>(); /** * All currently bound service connections. Keys are the IBinder of * the client's IServiceConnection. */ - final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections - = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>(); + final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections = new ArrayMap<>(); /** * List of services that we have been asked to start, @@ -134,20 +134,20 @@ public final class ActiveServices { * while waiting for their corresponding application thread to get * going. */ - final ArrayList<ServiceRecord> mPendingServices - = new ArrayList<ServiceRecord>(); + final ArrayList<ServiceRecord> mPendingServices = new ArrayList<>(); /** * List of services that are scheduled to restart following a crash. */ - final ArrayList<ServiceRecord> mRestartingServices - = new ArrayList<ServiceRecord>(); + final ArrayList<ServiceRecord> mRestartingServices = new ArrayList<>(); /** * List of services that are in the process of being destroyed. */ - final ArrayList<ServiceRecord> mDestroyingServices - = new ArrayList<ServiceRecord>(); + final ArrayList<ServiceRecord> mDestroyingServices = new ArrayList<>(); + + /** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */ + private ArrayList<ServiceRecord> mTmpCollectionResults = null; /** Amount of time to allow a last ANR message to exist before freeing the memory. */ static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // Two hours @@ -162,10 +162,6 @@ public final class ActiveServices { } }; - static final class DelayingProcess extends ArrayList<ServiceRecord> { - long timeoout; - } - /** * Information about services for a single user. */ @@ -2076,14 +2072,16 @@ public final class ActiveServices { } } - private boolean collectForceStopServicesLocked(String name, int userId, - boolean evenPersistent, boolean doit, - ArrayMap<ComponentName, ServiceRecord> services, - ArrayList<ServiceRecord> result) { + private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses, + boolean evenPersistent, boolean doit, ArrayMap<ComponentName, ServiceRecord> services) { boolean didSomething = false; - for (int i=0; i<services.size(); i++) { + for (int i = services.size() - 1; i >= 0; i--) { ServiceRecord service = services.valueAt(i); - if ((name == null || service.packageName.equals(name)) + final boolean sameComponent = packageName == null + || (service.packageName.equals(packageName) + && (filterByClasses == null + || filterByClasses.contains(service.name.getClassName()))); + if (sameComponent && (service.app == null || evenPersistent || !service.app.persistent)) { if (!doit) { return true; @@ -2098,19 +2096,27 @@ public final class ActiveServices { } service.app = null; service.isolatedProc = null; - result.add(service); + if (mTmpCollectionResults == null) { + mTmpCollectionResults = new ArrayList<>(); + } + mTmpCollectionResults.add(service); } } return didSomething; } - boolean forceStopLocked(String name, int userId, boolean evenPersistent, boolean doit) { + boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses, + int userId, boolean evenPersistent, boolean doit) { boolean didSomething = false; - ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); + + if (mTmpCollectionResults != null) { + mTmpCollectionResults.clear(); + } + if (userId == UserHandle.USER_ALL) { - for (int i=0; i<mServiceMap.size(); i++) { - didSomething |= collectForceStopServicesLocked(name, userId, evenPersistent, - doit, mServiceMap.valueAt(i).mServicesByName, services); + for (int i = mServiceMap.size() - 1; i >= 0; i--) { + didSomething |= collectPackageServicesLocked(packageName, filterByClasses, + evenPersistent, doit, mServiceMap.valueAt(i).mServicesByName); if (!doit && didSomething) { return true; } @@ -2119,22 +2125,24 @@ public final class ActiveServices { ServiceMap smap = mServiceMap.get(userId); if (smap != null) { ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByName; - didSomething = collectForceStopServicesLocked(name, userId, evenPersistent, - doit, items, services); + didSomething = collectPackageServicesLocked(packageName, filterByClasses, + evenPersistent, doit, items); } } - int N = services.size(); - for (int i=0; i<N; i++) { - bringDownServiceLocked(services.get(i)); + if (mTmpCollectionResults != null) { + for (int i = mTmpCollectionResults.size() - 1; i >= 0; i--) { + bringDownServiceLocked(mTmpCollectionResults.get(i)); + } + mTmpCollectionResults.clear(); } return didSomething; } void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) { - ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); + ArrayList<ServiceRecord> services = new ArrayList<>(); ArrayMap<ComponentName, ServiceRecord> alls = getServices(tr.userId); - for (int i=0; i<alls.size(); i++) { + for (int i = alls.size() - 1; i >= 0; i--) { ServiceRecord sr = alls.valueAt(i); if (sr.packageName.equals(component.getPackageName())) { services.add(sr); @@ -2142,7 +2150,7 @@ public final class ActiveServices { } // Take care of any running services associated with the app. - for (int i=0; i<services.size(); i++) { + for (int i = services.size() - 1; i >= 0; i--) { ServiceRecord sr = services.get(i); if (sr.startRequested) { if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 82dbfee..c38fc8d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -375,6 +375,10 @@ public final class ActivityManagerService extends ActivityManagerNative // Delay in notifying task stack change listeners (in millis) static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 1000; + // Necessary ApplicationInfo flags to mark an app as persistent + private static final int PERSISTENT_MASK = + ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT; + /** All system services */ SystemServiceManager mSystemServiceManager; @@ -5363,39 +5367,117 @@ public final class ActivityManagerService extends ActivityManagerNative return N > 0; } - private final boolean forceStopPackageLocked(String name, int appId, + private void cleanupDisabledPackageComponentsLocked( + String packageName, int userId, String[] changedClasses) { + + Set<String> disabledClasses = null; + boolean packageDisabled = false; + IPackageManager pm = AppGlobals.getPackageManager(); + + if (changedClasses == null) { + // Nothing changed... + return; + } + + // Determine enable/disable state of the package and its components. + int enabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + for (int i = changedClasses.length - 1; i >= 0; i--) { + final String changedClass = changedClasses[i]; + + if (changedClass.equals(packageName)) { + try { + // Entire package setting changed + enabled = pm.getApplicationEnabledSetting(packageName, + (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER); + } catch (RemoteException e) { + // Can't happen... + } + packageDisabled = enabled != PackageManager.COMPONENT_ENABLED_STATE_ENABLED + && enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + if (packageDisabled) { + // Entire package is disabled. + // No need to continue to check component states. + disabledClasses = null; + break; + } + } else { + try { + enabled = pm.getComponentEnabledSetting( + new ComponentName(packageName, changedClass), + (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER); + } catch (RemoteException e) { + // Can't happen... + } + if (enabled != PackageManager.COMPONENT_ENABLED_STATE_ENABLED + && enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + if (disabledClasses == null) { + disabledClasses = new ArraySet<>(changedClasses.length); + } + disabledClasses.add(changedClass); + } + } + } + + if (!packageDisabled && disabledClasses == null) { + // Nothing to do here... + return; + } + + // Clean-up disabled activities. + if (mStackSupervisor.finishDisabledPackageActivitiesLocked( + packageName, disabledClasses, true, false, userId) && mBooted) { + mStackSupervisor.resumeTopActivitiesLocked(); + mStackSupervisor.scheduleIdleLocked(); + } + + // Clean-up disabled tasks + cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId); + + // Clean-up disabled services. + mServices.bringDownDisabledPackageServicesLocked( + packageName, disabledClasses, userId, false, true); + + // Clean-up disabled providers. + ArrayList<ContentProviderRecord> providers = new ArrayList<>(); + mProviderMap.collectPackageProvidersLocked( + packageName, disabledClasses, true, false, userId, providers); + for (int i = providers.size() - 1; i >= 0; i--) { + removeDyingProviderLocked(null, providers.get(i), true); + } + } + + private final boolean forceStopPackageLocked(String packageName, int appId, boolean callerWillRestart, boolean purgeCache, boolean doit, boolean evenPersistent, boolean uninstalling, int userId, String reason) { int i; - int N; - if (userId == UserHandle.USER_ALL && name == null) { + if (userId == UserHandle.USER_ALL && packageName == null) { Slog.w(TAG, "Can't force stop all processes of all users, that is insane!"); } - if (appId < 0 && name != null) { + if (appId < 0 && packageName != null) { try { appId = UserHandle.getAppId( - AppGlobals.getPackageManager().getPackageUid(name, 0)); + AppGlobals.getPackageManager().getPackageUid(packageName, 0)); } catch (RemoteException e) { } } if (doit) { - if (name != null) { - Slog.i(TAG, "Force stopping " + name + " appid=" + appId + if (packageName != null) { + Slog.i(TAG, "Force stopping " + packageName + " appid=" + appId + " user=" + userId + ": " + reason); } else { Slog.i(TAG, "Force stopping u" + userId + ": " + reason); } final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap(); - for (int ip=pmap.size()-1; ip>=0; ip--) { + for (int ip = pmap.size() - 1; ip >= 0; ip--) { SparseArray<Long> ba = pmap.valueAt(ip); - for (i=ba.size()-1; i>=0; i--) { + for (i = ba.size() - 1; i >= 0; i--) { boolean remove = false; final int entUid = ba.keyAt(i); - if (name != null) { + if (packageName != null) { if (userId == UserHandle.USER_ALL) { if (UserHandle.getAppId(entUid) == appId) { remove = true; @@ -5418,46 +5500,47 @@ public final class ActivityManagerService extends ActivityManagerNative } } - boolean didSomething = killPackageProcessesLocked(name, appId, userId, + boolean didSomething = killPackageProcessesLocked(packageName, appId, userId, -100, callerWillRestart, true, doit, evenPersistent, - name == null ? ("stop user " + userId) : ("stop " + name)); + packageName == null ? ("stop user " + userId) : ("stop " + packageName)); - if (mStackSupervisor.forceStopPackageLocked(name, doit, evenPersistent, userId)) { + if (mStackSupervisor.finishDisabledPackageActivitiesLocked( + packageName, null, doit, evenPersistent, userId)) { if (!doit) { return true; } didSomething = true; } - if (mServices.forceStopLocked(name, userId, evenPersistent, doit)) { + if (mServices.bringDownDisabledPackageServicesLocked( + packageName, null, userId, evenPersistent, doit)) { if (!doit) { return true; } didSomething = true; } - if (name == null) { + if (packageName == null) { // Remove all sticky broadcasts from this user. mStickyBroadcasts.remove(userId); } - ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>(); - if (mProviderMap.collectForceStopProviders(name, appId, doit, evenPersistent, + ArrayList<ContentProviderRecord> providers = new ArrayList<>(); + if (mProviderMap.collectPackageProvidersLocked(packageName, null, doit, evenPersistent, userId, providers)) { if (!doit) { return true; } didSomething = true; } - N = providers.size(); - for (i=0; i<N; i++) { + for (i = providers.size() - 1; i >= 0; i--) { removeDyingProviderLocked(null, providers.get(i), true); } // Remove transient permissions granted from/to this package/user - removeUriPermissionsForPackageLocked(name, userId, false); + removeUriPermissionsForPackageLocked(packageName, userId, false); - if (name == null || uninstalling) { + if (packageName == null || uninstalling) { // Remove pending intents. For now we only do this when force // stopping users, because we have some problems when doing this // for packages -- app widgets are not currently cleaned up for @@ -5476,7 +5559,7 @@ public final class ActivityManagerService extends ActivityManagerNative it.remove(); continue; } - if (name == null) { + if (packageName == null) { // Stopping user, remove all objects for the user. if (pir.key.userId != userId) { // Not the same user, skip it. @@ -5491,7 +5574,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Different user, skip it. continue; } - if (!pir.key.packageName.equals(name)) { + if (!pir.key.packageName.equals(packageName)) { // Different package, skip it. continue; } @@ -5510,10 +5593,10 @@ public final class ActivityManagerService extends ActivityManagerNative } if (doit) { - if (purgeCache && name != null) { + if (purgeCache && packageName != null) { AttributeCache ac = AttributeCache.instance(); if (ac != null) { - ac.removePackage(name); + ac.removePackage(packageName); } } if (mBooted) { @@ -8331,29 +8414,20 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private void removeTasksByRemovedPackageComponentsLocked(String packageName, int userId) { - final IPackageManager pm = AppGlobals.getPackageManager(); - final HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>(); + private void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses, + int userId) { for (int i = mRecentTasks.size() - 1; i >= 0; i--) { TaskRecord tr = mRecentTasks.get(i); - if (tr.userId != userId) continue; + if (userId != UserHandle.USER_ALL && tr.userId != userId) { + continue; + } ComponentName cn = tr.intent.getComponent(); - if (cn != null && cn.getPackageName().equals(packageName)) { - // Skip if component still exists in the package. - if (componentsKnownToExist.contains(cn)) continue; - - try { - ActivityInfo info = pm.getActivityInfo(cn, 0, userId); - if (info != null) { - componentsKnownToExist.add(cn); - } else { - removeTaskByIdLocked(tr.taskId, false); - } - } catch (RemoteException e) { - Log.e(TAG, "Activity info query failed. component=" + cn, e); - } + final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName) + && (filterByClasses == null || filterByClasses.contains(cn.getClassName())); + if (sameComponent) { + removeTaskByIdLocked(tr.taskId, false); } } } @@ -9773,10 +9847,10 @@ public final class ActivityManagerService extends ActivityManagerNative 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; if (isolated) { if (isolatedUid == 0) { - int userId = UserHandle.getUserId(uid); int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1; while (true) { if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID @@ -9800,7 +9874,13 @@ public final class ActivityManagerService extends ActivityManagerNative uid = isolatedUid; } } - return new ProcessRecord(stats, info, proc, uid); + final ProcessRecord r = new ProcessRecord(stats, info, proc, uid); + if (!mBooted && !mBooting + && userId == UserHandle.USER_OWNER + && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { + r.persistent = true; + } + return r; } final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated, @@ -9832,8 +9912,7 @@ public final class ActivityManagerService extends ActivityManagerNative + info.packageName + ": " + e); } - if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) - == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) { + if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { app.persistent = true; app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; } @@ -14121,6 +14200,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean dumpDetails = false; boolean dumpFullDetails = false; boolean dumpDalvik = false; + boolean dumpSummaryOnly = false; boolean oomOnly = false; boolean isCompact = false; boolean localOnly = false; @@ -14141,6 +14221,9 @@ public final class ActivityManagerService extends ActivityManagerNative dumpDalvik = true; } else if ("-c".equals(opt)) { isCompact = true; + } else if ("-s".equals(opt)) { + dumpDetails = true; + dumpSummaryOnly = true; } else if ("--oom".equals(opt)) { oomOnly = true; } else if ("--local".equals(opt)) { @@ -14148,10 +14231,11 @@ public final class ActivityManagerService extends ActivityManagerNative } else if ("--package".equals(opt)) { packages = true; } else if ("-h".equals(opt)) { - pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]"); + pw.println("meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]"); pw.println(" -a: include all available information for each process."); pw.println(" -d: include dalvik details."); pw.println(" -c: dump in a compact machine-parseable representation."); + pw.println(" -s: dump only summary of application memory usage."); pw.println(" --oom: only show processes organized by oom adj."); pw.println(" --local: only collect details locally, don't call process."); pw.println(" --package: interpret process arg as package, dumping all"); @@ -14212,7 +14296,7 @@ public final class ActivityManagerService extends ActivityManagerNative mi.dalvikPrivateDirty = (int)tmpLong[0]; } ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails, - dumpDalvik, pid, r.baseName, 0, 0, 0, 0, 0, 0); + dumpDalvik, dumpSummaryOnly, pid, r.baseName, 0, 0, 0, 0, 0, 0); if (isCheckinRequest) { pw.println(); } @@ -14278,7 +14362,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (dumpDetails) { if (localOnly) { ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails, - dumpDalvik, pid, r.processName, 0, 0, 0, 0, 0, 0); + dumpDalvik, dumpSummaryOnly, pid, r.processName, 0, 0, 0, 0, 0, 0); if (isCheckinRequest) { pw.println(); } @@ -14286,7 +14370,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { pw.flush(); thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails, - dumpDalvik, innerArgs); + dumpDalvik, dumpSummaryOnly, innerArgs); } catch (RemoteException e) { if (!isCheckinRequest) { pw.println("Got RemoteException!"); @@ -16071,7 +16155,9 @@ public final class ActivityManagerService extends ActivityManagerNative mBatteryStatsService.notePackageUninstalled(ssp); } } else { - removeTasksByRemovedPackageComponentsLocked(ssp, userId); + cleanupDisabledPackageComponentsLocked(ssp, userId, + intent.getStringArrayExtra( + Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST)); if (userId == UserHandle.USER_OWNER) { mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp); } @@ -16089,9 +16175,6 @@ public final class ActivityManagerService extends ActivityManagerNative intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); mCompatModePackages.handlePackageAddedLocked(ssp, replacing); - if (replacing) { - removeTasksByRemovedPackageComponentsLocked(ssp, userId); - } if (userId == UserHandle.USER_OWNER) { mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp); } @@ -16823,6 +16906,9 @@ public final class ActivityManagerService extends ActivityManagerNative if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) { intent = new Intent(Intent.ACTION_LOCALE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + if (!mProcessesReady) { + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); @@ -19407,7 +19493,7 @@ public final class ActivityManagerService extends ActivityManagerNative mStackSupervisor.resumeTopActivitiesLocked(); } EventLogTags.writeAmSwitchUser(newUserId); - getUserManagerLocked().userForeground(newUserId); + getUserManagerLocked().onUserForeground(newUserId); sendUserSwitchBroadcastsLocked(oldUserId, newUserId); } @@ -19868,6 +19954,14 @@ public final class ActivityManagerService extends ActivityManagerNative return token; } } + + @Override + public ComponentName getHomeActivityForUser(int userId) { + synchronized (ActivityManagerService.this) { + ActivityRecord homeActivity = mStackSupervisor.getHomeActivityForUser(userId); + return homeActivity == null ? null : homeActivity.realActivity; + } + } } private final class SleepTokenImpl extends SleepToken { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 951b9a9..6574538 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -81,6 +81,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.Set; /** * State and management of a single stack of activities. @@ -4008,7 +4009,8 @@ final class ActivityStack { } } - boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) { + boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses, + boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; TaskRecord lastTask = null; ComponentName homeActivity = null; @@ -4017,10 +4019,12 @@ final class ActivityStack { int numActivities = activities.size(); for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { ActivityRecord r = activities.get(activityNdx); - final boolean samePackage = r.packageName.equals(name) - || (name == null && r.userId == userId); + final boolean sameComponent = + (r.packageName.equals(packageName) && (filterByClasses == null + || filterByClasses.contains(r.realActivity.getClassName()))) + || (packageName == null && r.userId == userId); if ((userId == UserHandle.USER_ALL || r.userId == userId) - && (samePackage || r.task == lastTask) + && (sameComponent || r.task == lastTask) && (r.app == null || evenPersistent || !r.app.persistent)) { if (!doit) { if (r.finishing) { @@ -4040,7 +4044,7 @@ final class ActivityStack { } didSomething = true; Slog.i(TAG, " Force finishing activity " + r); - if (samePackage) { + if (sameComponent) { if (r.app != null) { r.app.removed = true; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 8c98f9f..cb5ba8e 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -118,6 +118,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Set; public final class ActivityStackSupervisor implements DisplayListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM; @@ -2507,14 +2508,16 @@ public final class ActivityStackSupervisor implements DisplayListener { /** * @return true if some activity was finished (or would have finished if doit were true). */ - boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) { + boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses, + boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; final int numStacks = stacks.size(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { final ActivityStack stack = stacks.get(stackNdx); - if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) { + if (stack.finishDisabledPackageActivitiesLocked( + packageName, filterByClasses, doit, evenPersistent, userId)) { didSomething = true; } } @@ -2653,6 +2656,10 @@ public final class ActivityStackSupervisor implements DisplayListener { } ActivityRecord getHomeActivity() { + return getHomeActivityForUser(UserHandle.USER_ALL); + } + + ActivityRecord getHomeActivityForUser(int userId) { final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = tasks.get(taskNdx); @@ -2660,7 +2667,8 @@ public final class ActivityStackSupervisor implements DisplayListener { final ArrayList<ActivityRecord> activities = task.mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { final ActivityRecord r = activities.get(activityNdx); - if (r.isHomeActivity()) { + if (r.isHomeActivity() + && ((userId == UserHandle.USER_ALL) || (r.userId == userId))) { return r; } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index e5c5dff..e89ef57 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -85,7 +85,7 @@ public final class BroadcastQueue { * a bunch of processes to execute IntentReceiver components. Background- * and foreground-priority broadcasts are queued separately. */ - final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>(); + final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>(); /** * List of all active broadcasts that are to be executed one at a time. @@ -94,7 +94,7 @@ public final class BroadcastQueue { * broadcasts, separate background- and foreground-priority queues are * maintained. */ - final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>(); + final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>(); /** * Historical data of past broadcasts, for debugging. This is a ring buffer diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java index 7da8c48..a1dc3e3 100644 --- a/services/core/java/com/android/server/am/ProviderMap.java +++ b/services/core/java/com/android/server/am/ProviderMap.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Set; /** * Keeps track of content providers by authority (name) and class. It separates the mapping by @@ -184,13 +185,17 @@ public final class ProviderMap { } } - private boolean collectForceStopProvidersLocked(String name, int appId, - boolean doit, boolean evenPersistent, int userId, + private boolean collectPackageProvidersLocked(String packageName, + Set<String> filterByClasses, boolean doit, boolean evenPersistent, HashMap<ComponentName, ContentProviderRecord> providers, ArrayList<ContentProviderRecord> result) { boolean didSomething = false; for (ContentProviderRecord provider : providers.values()) { - if ((name == null || provider.info.packageName.equals(name)) + final boolean sameComponent = packageName == null + || (provider.info.packageName.equals(packageName) + && (filterByClasses == null + || filterByClasses.contains(provider.name.getClassName()))); + if (sameComponent && (provider.proc == null || evenPersistent || !provider.proc.persistent)) { if (!doit) { return true; @@ -202,18 +207,18 @@ public final class ProviderMap { return didSomething; } - boolean collectForceStopProviders(String name, int appId, + boolean collectPackageProvidersLocked(String packageName, Set<String> filterByClasses, boolean doit, boolean evenPersistent, int userId, ArrayList<ContentProviderRecord> result) { - boolean didSomething = collectForceStopProvidersLocked(name, appId, doit, - evenPersistent, userId, mSingletonByClass, result); + boolean didSomething = collectPackageProvidersLocked(packageName, filterByClasses, + doit, evenPersistent, mSingletonByClass, result); if (!doit && didSomething) { return true; } if (userId == UserHandle.USER_ALL) { - for (int i=0; i<mProvidersByClassPerUser.size(); i++) { - if (collectForceStopProvidersLocked(name, appId, doit, evenPersistent, - userId, mProvidersByClassPerUser.valueAt(i), result)) { + for (int i = 0; i < mProvidersByClassPerUser.size(); i++) { + if (collectPackageProvidersLocked(packageName, filterByClasses, + doit, evenPersistent, mProvidersByClassPerUser.valueAt(i), result)) { if (!doit) { return true; } @@ -224,8 +229,8 @@ public final class ProviderMap { HashMap<ComponentName, ContentProviderRecord> items = getProvidersByClass(userId); if (items != null) { - didSomething |= collectForceStopProvidersLocked(name, appId, doit, - evenPersistent, userId, items, result); + didSomething |= collectPackageProvidersLocked(packageName, filterByClasses, + doit, evenPersistent, items, result); } } return didSomething; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 06fba34..2149b7a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -20,9 +20,13 @@ import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK; import static android.media.AudioManager.RINGER_MODE_NORMAL; import static android.media.AudioManager.RINGER_MODE_SILENT; import static android.media.AudioManager.RINGER_MODE_VIBRATE; +import static android.os.Process.FIRST_APPLICATION_UID; +import android.Manifest; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; +import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.KeyguardManager; import android.bluetooth.BluetoothA2dp; @@ -37,7 +41,10 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -82,11 +89,13 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; import android.os.Vibrator; import android.provider.Settings; import android.provider.Settings.System; import android.telecom.TelecomManager; import android.text.TextUtils; +import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -102,6 +111,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.util.XmlUtils; import com.android.server.EventLogTags; import com.android.server.LocalServices; +import com.android.server.pm.UserManagerService; import org.xmlpull.v1.XmlPullParserException; @@ -645,6 +655,8 @@ public class AudioService extends IAudioService.Stub { intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_USER_SWITCHED); + intentFilter.addAction(Intent.ACTION_USER_BACKGROUND); + intentFilter.addAction(Intent.ACTION_USER_FOREGROUND); intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); @@ -668,7 +680,7 @@ public class AudioService extends IAudioService.Stub { setRotationForAudioSystem(); } - context.registerReceiver(mReceiver, intentFilter); + context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null); LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal()); } @@ -4975,10 +4987,62 @@ public class AudioService extends IAudioService.Stub { 0, 0, mStreamStates[AudioSystem.STREAM_MUSIC], 0); + } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) { + // Disable audio recording for the background user/profile + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (userId >= 0) { + // TODO Kill recording streams instead of killing processes holding permission + UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId); + killBackgroundUserProcessesWithRecordAudioPermission(userInfo); + } + UserManagerService.getInstance().setSystemControlledUserRestriction( + UserManager.DISALLOW_RECORD_AUDIO, true, userId); + } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) { + // Enable audio recording for foreground user/profile + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + UserManagerService.getInstance().setSystemControlledUserRestriction( + UserManager.DISALLOW_RECORD_AUDIO, false, userId); } } } // end class AudioServiceBroadcastReceiver + private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) { + PackageManager pm = mContext.getPackageManager(); + // Find the home activity of the user. It should not be killed to avoid expensive restart, + // when the user switches back. For managed profiles, we should kill all recording apps + ComponentName homeActivityName = null; + if (!oldUser.isManagedProfile()) { + homeActivityName = LocalServices.getService(ActivityManagerInternal.class) + .getHomeActivityForUser(oldUser.id); + } + final String[] permissions = { Manifest.permission.RECORD_AUDIO }; + List<PackageInfo> packages; + try { + packages = AppGlobals.getPackageManager() + .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList(); + } catch (RemoteException e) { + throw new AndroidRuntimeException(e); + } + for (int j = packages.size() - 1; j >= 0; j--) { + PackageInfo pkg = packages.get(j); + // Skip system processes + if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) { + continue; + } + if (homeActivityName != null + && pkg.packageName.equals(homeActivityName.getPackageName()) + && pkg.applicationInfo.isSystemApp()) { + continue; + } + try { + ActivityManagerNative.getDefault().killUid(pkg.applicationInfo.uid, + "killBackgroundUserProcessesWithAudioRecordPermission"); + } catch (RemoteException e) { + Log.w(TAG, "Error calling killUid", e); + } + } + } + //========================================================================================== // RemoteControlDisplay / RemoteControlClient / Remote info //========================================================================================== diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index ac55292..aeecdf3 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -217,14 +217,21 @@ public class Vpn { * @return true if the operation is succeeded. */ public synchronized boolean prepare(String oldPackage, String newPackage) { - if (oldPackage != null && getAppUid(oldPackage, mUserHandle) != mOwnerUID) { - // The package doesn't match. We return false (to obtain user consent) unless the user - // has already consented to that VPN package. - if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) { - prepareInternal(oldPackage); - return true; + if (oldPackage != null) { + if (getAppUid(oldPackage, mUserHandle) != mOwnerUID) { + // The package doesn't match. We return false (to obtain user consent) unless the + // user has already consented to that VPN package. + if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) { + prepareInternal(oldPackage); + return true; + } + return false; + } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN) + && !isVpnUserPreConsented(oldPackage)) { + // Currently prepared VPN is revoked, so unprepare it and return false. + prepareInternal(VpnConfig.LEGACY_VPN); + return false; } - return false; } // Return true if we do not need to revoke. @@ -481,6 +488,10 @@ public class Vpn { if (Binder.getCallingUid() != mOwnerUID) { return null; } + // Check to ensure consent hasn't been revoked since we were prepared. + if (!isVpnUserPreConsented(mPackage)) { + return null; + } // Check if the service is properly declared. Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); intent.setClassName(mPackage, config.user); diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java index b411a0d..6ba25a5 100644 --- a/services/core/java/com/android/server/display/DisplayAdapter.java +++ b/services/core/java/com/android/server/display/DisplayAdapter.java @@ -18,8 +18,10 @@ package com.android.server.display; import android.content.Context; import android.os.Handler; +import android.view.Display; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicInteger; /** * A display adapter makes zero or more display devices available to the system @@ -42,6 +44,11 @@ abstract class DisplayAdapter { public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2; public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3; + /** + * Used to generate globally unique display mode ids. + */ + private static final AtomicInteger NEXT_DISPLAY_MODE_ID = new AtomicInteger(1); // 0 = no mode. + // Called with SyncRoot lock held. public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, String name) { @@ -122,6 +129,11 @@ abstract class DisplayAdapter { }); } + public static Display.Mode createMode(int width, int height, float refreshRate) { + return new Display.Mode( + NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate); + } + public interface Listener { public void onDisplayDeviceEvent(DisplayDevice device, int event); public void onTraversalRequested(); diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index ee36972..93bda46 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -19,6 +19,7 @@ package com.android.server.display; import android.graphics.Rect; import android.hardware.display.DisplayViewport; import android.os.IBinder; +import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; @@ -132,9 +133,9 @@ abstract class DisplayDevice { } /** - * Sets the refresh rate, if supported. + * Sets the mode, if supported. */ - public void requestRefreshRateLocked(float refreshRate) { + public void requestModeInTransactionLocked(int id) { } /** diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index ebf6e4e..0db3e3f 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -23,7 +23,6 @@ import android.view.Surface; import java.util.Arrays; -import libcore.util.EmptyArray; import libcore.util.Objects; /** @@ -137,14 +136,19 @@ final class DisplayDeviceInfo { public int height; /** - * The refresh rate of the display, in frames per second. + * The active mode of the display. */ - public float refreshRate; + public int modeId; /** - * The supported refresh rates of the display at the current resolution in frames per second. + * The default mode of the display. */ - public float[] supportedRefreshRates = EmptyArray.FLOAT; + public int defaultModeId; + + /** + * The supported modes of the display. + */ + public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY; /** * The nominal apparent density of the display in DPI used for layout calculations. @@ -264,8 +268,9 @@ final class DisplayDeviceInfo { || !Objects.equal(uniqueId, other.uniqueId) || width != other.width || height != other.height - || refreshRate != other.refreshRate - || !Arrays.equals(supportedRefreshRates, other.supportedRefreshRates) + || modeId != other.modeId + || defaultModeId != other.defaultModeId + || !Arrays.equals(supportedModes, other.supportedModes) || densityDpi != other.densityDpi || xDpi != other.xDpi || yDpi != other.yDpi @@ -293,8 +298,9 @@ final class DisplayDeviceInfo { uniqueId = other.uniqueId; width = other.width; height = other.height; - refreshRate = other.refreshRate; - supportedRefreshRates = other.supportedRefreshRates; + modeId = other.modeId; + defaultModeId = other.defaultModeId; + supportedModes = other.supportedModes; densityDpi = other.densityDpi; xDpi = other.xDpi; yDpi = other.yDpi; @@ -317,8 +323,9 @@ final class DisplayDeviceInfo { sb.append("DisplayDeviceInfo{\""); sb.append(name).append("\": uniqueId=\"").append(uniqueId).append("\", "); sb.append(width).append(" x ").append(height); - sb.append(", ").append(refreshRate).append(" fps"); - sb.append(", supportedRefreshRates ").append(Arrays.toString(supportedRefreshRates)); + sb.append(", modeId ").append(modeId); + sb.append(", defaultModeId ").append(defaultModeId); + sb.append(", supportedModes ").append(Arrays.toString(supportedModes)); sb.append(", density ").append(densityDpi); sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi"); sb.append(", appVsyncOff ").append(appVsyncOffsetNanos); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 1e87433..7440b8c 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -842,7 +842,7 @@ public final class DisplayManagerService extends SystemService { } private void setDisplayPropertiesInternal(int displayId, boolean hasContent, - float requestedRefreshRate, boolean inTraversal) { + float requestedRefreshRate, int requestedModeId, boolean inTraversal) { synchronized (mSyncRoot) { LogicalDisplay display = mLogicalDisplays.get(displayId); if (display == null) { @@ -857,12 +857,17 @@ public final class DisplayManagerService extends SystemService { display.setHasContentLocked(hasContent); scheduleTraversalLocked(inTraversal); } - if (display.getRequestedRefreshRateLocked() != requestedRefreshRate) { + if (requestedModeId == 0 && requestedRefreshRate != 0) { + // Scan supported modes returned by display.getInfo() to find a mode with the same + // size as the default display mode but with the specified refresh rate instead. + requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate( + requestedRefreshRate); + } + if (display.getRequestedModeIdLocked() != requestedModeId) { if (DEBUG) { - Slog.d(TAG, "Display " + displayId + " has requested a new refresh rate: " - + requestedRefreshRate + "fps"); + Slog.d(TAG, "Display " + displayId + " switching to mode " + requestedModeId); } - display.setRequestedRefreshRateLocked(requestedRefreshRate); + display.setRequestedModeIdLocked(requestedModeId); scheduleTraversalLocked(inTraversal); } } @@ -1564,8 +1569,9 @@ public final class DisplayManagerService extends SystemService { @Override public void setDisplayProperties(int displayId, boolean hasContent, - float requestedRefreshRate, boolean inTraversal) { - setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal); + float requestedRefreshRate, int requestedMode, boolean inTraversal) { + setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, + requestedMode, inTraversal); } @Override diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index e87f265..cc7d848 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -35,7 +35,7 @@ import android.view.Surface; import android.view.SurfaceControl; import java.io.PrintWriter; -import java.util.Arrays; +import java.util.ArrayList; /** * A display adapter for the local displays managed by Surface Flinger. @@ -56,6 +56,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final SparseArray<LocalDisplayDevice> mDevices = new SparseArray<LocalDisplayDevice>(); + @SuppressWarnings("unused") // Becomes active at instantiation time. private HotplugDisplayEventReceiver mHotplugReceiver; // Called with SyncRoot lock held. @@ -136,28 +137,22 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final class LocalDisplayDevice extends DisplayDevice { private final int mBuiltInDisplayId; - private final SurfaceControl.PhysicalDisplayInfo mPhys; - private final int mDefaultPhysicalDisplayInfo; private final Light mBacklight; + private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>(); private DisplayDeviceInfo mInfo; private boolean mHavePendingChanges; private int mState = Display.STATE_UNKNOWN; private int mBrightness = PowerManager.BRIGHTNESS_DEFAULT; - private float[] mSupportedRefreshRates; - private int[] mRefreshRateConfigIndices; - private float mLastRequestedRefreshRate; - + private int mDefaultModeId; + private int mActiveModeId; + private boolean mActiveModeInvalid; public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId, SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId); mBuiltInDisplayId = builtInDisplayId; - mPhys = new SurfaceControl.PhysicalDisplayInfo( - physicalDisplayInfos[activeDisplayInfo]); - mDefaultPhysicalDisplayInfo = activeDisplayInfo; - updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys); - + updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo); if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { LightsManager lights = LocalServices.getService(LightsManager.class); mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT); @@ -168,14 +163,73 @@ final class LocalDisplayAdapter extends DisplayAdapter { public boolean updatePhysicalDisplayInfoLocked( SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) { - SurfaceControl.PhysicalDisplayInfo newPhys = physicalDisplayInfos[activeDisplayInfo]; - if (!mPhys.equals(newPhys)) { - mPhys.copyFrom(newPhys); - updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys); - mHavePendingChanges = true; - return true; + // Build an updated list of all existing modes. + boolean modesAdded = false; + DisplayModeRecord activeRecord = null; + ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>(); + for (int i = 0; i < physicalDisplayInfos.length; i++) { + SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i]; + DisplayModeRecord record = findDisplayModeRecord(info); + if (record != null) { + record.mPhysIndex = i; + } else { + record = new DisplayModeRecord(info, i); + modesAdded = true; + } + records.add(record); + if (i == activeDisplayInfo) { + activeRecord = record; + } + } + // Check whether surface flinger spontaneously changed modes out from under us. Schedule + // traversals to ensure that the correct state is reapplied if necessary. + if (mActiveModeId != 0 + && mActiveModeId != activeRecord.mMode.getModeId()) { + mActiveModeInvalid = true; + sendTraversalRequestLocked(); + } + // If no modes were added and we have the same number of modes as before, then nothing + // actually changed except possibly the physical index (which we only care about when + // setting the mode) so we're done. + if (records.size() == mSupportedModes.size() && !modesAdded) { + return false; + } + // Update the index of modes. + mHavePendingChanges = true; + mSupportedModes.clear(); + for (DisplayModeRecord record : records) { + mSupportedModes.put(record.mMode.getModeId(), record); + } + // Update the default mode if needed. + if (mSupportedModes.indexOfKey(mDefaultModeId) < 0) { + if (mDefaultModeId != 0) { + Slog.w(TAG, "Default display mode no longer available, using currently active" + + " mode as default."); + } + mDefaultModeId = activeRecord.mMode.getModeId(); + } + // Determine whether the active mode is still there. + if (mSupportedModes.indexOfKey(mActiveModeId) < 0) { + if (mActiveModeId != 0) { + Slog.w(TAG, "Active display mode no longer available, reverting to default" + + " mode."); + } + mActiveModeId = mDefaultModeId; + mActiveModeInvalid = true; + } + // Schedule traversals so that we apply pending changes. + sendTraversalRequestLocked(); + return true; + } + + private DisplayModeRecord findDisplayModeRecord(SurfaceControl.PhysicalDisplayInfo info) { + for (int i = 0; i < mSupportedModes.size(); i++) { + DisplayModeRecord record = mSupportedModes.valueAt(i); + if (record.mPhys.equals(info)) { + return record; + } } - return false; + return null; } @Override @@ -189,19 +243,25 @@ final class LocalDisplayAdapter extends DisplayAdapter { @Override public DisplayDeviceInfo getDisplayDeviceInfoLocked() { if (mInfo == null) { + SurfaceControl.PhysicalDisplayInfo phys = mSupportedModes.get(mActiveModeId).mPhys; mInfo = new DisplayDeviceInfo(); - mInfo.width = mPhys.width; - mInfo.height = mPhys.height; - mInfo.refreshRate = mPhys.refreshRate; - mInfo.supportedRefreshRates = mSupportedRefreshRates; - mInfo.appVsyncOffsetNanos = mPhys.appVsyncOffsetNanos; - mInfo.presentationDeadlineNanos = mPhys.presentationDeadlineNanos; + mInfo.width = phys.width; + mInfo.height = phys.height; + mInfo.modeId = mActiveModeId; + mInfo.defaultModeId = mDefaultModeId; + mInfo.supportedModes = new Display.Mode[mSupportedModes.size()]; + for (int i = 0; i < mSupportedModes.size(); i++) { + DisplayModeRecord record = mSupportedModes.valueAt(i); + mInfo.supportedModes[i] = record.mMode; + } + mInfo.appVsyncOffsetNanos = phys.appVsyncOffsetNanos; + mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos; mInfo.state = mState; mInfo.uniqueId = getUniqueId(); // Assume that all built-in displays that have secure output (eg. HDCP) also // support compositing from gralloc protected buffers. - if (mPhys.secure) { + if (phys.secure) { mInfo.flags = DisplayDeviceInfo.FLAG_SECURE | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; } @@ -212,9 +272,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; mInfo.type = Display.TYPE_BUILT_IN; - mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f); - mInfo.xDpi = mPhys.xDpi; - mInfo.yDpi = mPhys.yDpi; + mInfo.densityDpi = (int)(phys.density * 160 + 0.5f); + mInfo.xDpi = phys.xDpi; + mInfo.yDpi = phys.yDpi; mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; } else { mInfo.type = Display.TYPE_HDMI; @@ -222,7 +282,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.name = getContext().getResources().getString( com.android.internal.R.string.display_manager_hdmi_display_name); mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; - mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height); + mInfo.setAssumedDensityForExternalDisplay(phys.width, phys.height); // For demonstration purposes, allow rotation of the external display. // In the future we might allow the user to configure this directly. @@ -332,30 +392,29 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void requestRefreshRateLocked(float refreshRate) { - if (mLastRequestedRefreshRate == refreshRate) { - return; + public void requestModeInTransactionLocked(int modeId) { + if (modeId == 0) { + modeId = mDefaultModeId; + } else if (mSupportedModes.indexOfKey(modeId) < 0) { + Slog.w(TAG, "Requested mode " + modeId + " is not supported by this display," + + " reverting to default display mode."); + modeId = mDefaultModeId; } - mLastRequestedRefreshRate = refreshRate; - if (refreshRate != 0) { - final int N = mSupportedRefreshRates.length; - for (int i = 0; i < N; i++) { - if (refreshRate == mSupportedRefreshRates[i]) { - final int configIndex = mRefreshRateConfigIndices[i]; - SurfaceControl.setActiveConfig(getDisplayTokenLocked(), configIndex); - return; - } - } - Slog.w(TAG, "Requested refresh rate " + refreshRate + " is unsupported."); + if (mActiveModeId == modeId && !mActiveModeInvalid) { + return; } - SurfaceControl.setActiveConfig(getDisplayTokenLocked(), mDefaultPhysicalDisplayInfo); + DisplayModeRecord record = mSupportedModes.get(modeId); + SurfaceControl.setActiveConfig(getDisplayTokenLocked(), record.mPhysIndex); + mActiveModeId = modeId; + mActiveModeInvalid = false; + updateDeviceInfoLocked(); } @Override public void dumpLocked(PrintWriter pw) { super.dumpLocked(pw); pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); - pw.println("mPhys=" + mPhys); + pw.println("mActiveModeId=" + mActiveModeId); pw.println("mState=" + Display.stateToString(mState)); pw.println("mBrightness=" + mBrightness); pw.println("mBacklight=" + mBacklight); @@ -365,29 +424,20 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo = null; sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); } + } - private void updateSupportedRefreshRatesLocked( - SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, - SurfaceControl.PhysicalDisplayInfo activePhys) { - final int N = physicalDisplayInfos.length; - int idx = 0; - mSupportedRefreshRates = new float[N]; - mRefreshRateConfigIndices = new int[N]; - for (int i = 0; i < N; i++) { - final SurfaceControl.PhysicalDisplayInfo phys = physicalDisplayInfos[i]; - if (activePhys.width == phys.width - && activePhys.height == phys.height - && activePhys.density == phys.density - && activePhys.xDpi == phys.xDpi - && activePhys.yDpi == phys.yDpi) { - mSupportedRefreshRates[idx] = phys.refreshRate; - mRefreshRateConfigIndices[idx++] = i; - } - } - if (idx != N) { - mSupportedRefreshRates = Arrays.copyOfRange(mSupportedRefreshRates, 0, idx); - mRefreshRateConfigIndices = Arrays.copyOfRange(mRefreshRateConfigIndices, 0, idx); - } + /** + * Keeps track of a display configuration. + */ + private static final class DisplayModeRecord { + public final Display.Mode mMode; + public final SurfaceControl.PhysicalDisplayInfo mPhys; + public int mPhysIndex; + + public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys, int physIndex) { + mMode = createMode(phys.width, phys.height, phys.refreshRate); + mPhys = phys; + mPhysIndex = physIndex; } } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 65dc72f..7accbf2 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -73,8 +73,7 @@ final class LogicalDisplay { // True if the logical display has unique content. private boolean mHasContent; - // The pending requested refresh rate. 0 if no request is pending. - private float mRequestedRefreshRate; + private int mRequestedModeId; // The display offsets to apply to the display projection. private int mDisplayOffsetX; @@ -219,9 +218,10 @@ final class LogicalDisplay { mBaseDisplayInfo.logicalWidth = deviceInfo.width; mBaseDisplayInfo.logicalHeight = deviceInfo.height; mBaseDisplayInfo.rotation = Surface.ROTATION_0; - mBaseDisplayInfo.refreshRate = deviceInfo.refreshRate; - mBaseDisplayInfo.supportedRefreshRates = Arrays.copyOf( - deviceInfo.supportedRefreshRates, deviceInfo.supportedRefreshRates.length); + mBaseDisplayInfo.modeId = deviceInfo.modeId; + mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId; + mBaseDisplayInfo.supportedModes = Arrays.copyOf( + deviceInfo.supportedModes, deviceInfo.supportedModes.length); mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi; mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi; mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi; @@ -259,14 +259,19 @@ final class LogicalDisplay { */ public void configureDisplayInTransactionLocked(DisplayDevice device, boolean isBlanked) { - final DisplayInfo displayInfo = getDisplayInfoLocked(); - final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked(); - // Set the layer stack. device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack); - // Set the refresh rate - device.requestRefreshRateLocked(mRequestedRefreshRate); + // Set the mode. + if (device == mPrimaryDisplayDevice) { + device.requestModeInTransactionLocked(mRequestedModeId); + } else { + device.requestModeInTransactionLocked(0); // Revert to default. + } + + // Only grab the display info now as it may have been changed based on the requests above. + final DisplayInfo displayInfo = getDisplayInfoLocked(); + final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked(); // Set the viewport. // This is the area of the logical display that we intend to show on the @@ -351,20 +356,17 @@ final class LogicalDisplay { } /** - * Requests the given refresh rate. - * @param requestedRefreshRate The desired refresh rate. + * Requests the given mode. */ - public void setRequestedRefreshRateLocked(float requestedRefreshRate) { - mRequestedRefreshRate = requestedRefreshRate; + public void setRequestedModeIdLocked(int modeId) { + mRequestedModeId = modeId; } /** - * Gets the pending requested refresh rate. - * - * @return The pending refresh rate requested + * Returns the pending requested mode. */ - public float getRequestedRefreshRateLocked() { - return mRequestedRefreshRate; + public int getRequestedModeIdLocked() { + return mRequestedModeId; } /** @@ -393,7 +395,7 @@ final class LogicalDisplay { pw.println("mDisplayId=" + mDisplayId); pw.println("mLayerStack=" + mLayerStack); pw.println("mHasContent=" + mHasContent); - pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate); + pw.println("mRequestedMode=" + mRequestedModeId); pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")"); pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ? mPrimaryDisplayDevice.getNameLocked() : "null")); diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index af9f456..080665a 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -197,6 +197,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { private final long mDisplayPresentationDeadlineNanos; private final int mDensityDpi; private final boolean mSecure; + private final Display.Mode mMode; private int mState; private SurfaceTexture mSurfaceTexture; @@ -217,6 +218,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mSecure = secure; mState = state; mSurfaceTexture = surfaceTexture; + mMode = createMode(width, height, refreshRate); } public void destroyLocked() { @@ -251,8 +253,9 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mInfo.uniqueId = getUniqueId(); mInfo.width = mWidth; mInfo.height = mHeight; - mInfo.refreshRate = mRefreshRate; - mInfo.supportedRefreshRates = new float[] { mRefreshRate }; + mInfo.modeId = mMode.getModeId(); + mInfo.defaultModeId = mMode.getModeId(); + mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.densityDpi = mDensityDpi; mInfo.xDpi = mDensityDpi; mInfo.yDpi = mDensityDpi; diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java index 3f4eab9..786889a 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java +++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java @@ -302,7 +302,8 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { - mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate, + mListener.onWindowCreated(surfaceTexture, + mDefaultDisplayInfo.getMode().getRefreshRate(), mDefaultDisplayInfo.presentationDeadlineNanos, mDefaultDisplayInfo.state); } @@ -377,4 +378,4 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { public void onWindowDestroyed(); public void onStateChanged(int state); } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 7f961ae..986efd6 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -165,6 +165,8 @@ final class VirtualDisplayAdapter extends DisplayAdapter { private static final int PENDING_SURFACE_CHANGE = 0x01; private static final int PENDING_RESIZE = 0x02; + private static final float REFRESH_RATE = 60.0f; + private final IBinder mAppToken; private final int mOwnerUid; final String mOwnerPackageName; @@ -181,6 +183,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { private boolean mStopped; private int mPendingChanges; private int mUniqueIndex; + private Display.Mode mMode; public VirtualDisplayDevice(IBinder displayToken, IBinder appToken, int ownerUid, String ownerPackageName, @@ -193,6 +196,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { mName = name; mWidth = width; mHeight = height; + mMode = createMode(width, height, REFRESH_RATE); mDensityDpi = densityDpi; mSurface = surface; mFlags = flags; @@ -262,6 +266,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { sendTraversalRequestLocked(); mWidth = width; mHeight = height; + mMode = createMode(width, height, REFRESH_RATE); mDensityDpi = densityDpi; mInfo = null; mPendingChanges |= PENDING_RESIZE; @@ -290,12 +295,13 @@ final class VirtualDisplayAdapter extends DisplayAdapter { mInfo.uniqueId = getUniqueId(); mInfo.width = mWidth; mInfo.height = mHeight; - mInfo.refreshRate = 60; - mInfo.supportedRefreshRates = new float[] { 60.0f }; + mInfo.modeId = mMode.getModeId(); + mInfo.defaultModeId = mMode.getModeId(); + mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.densityDpi = mDensityDpi; mInfo.xDpi = mDensityDpi; mInfo.yDpi = mDensityDpi; - mInfo.presentationDeadlineNanos = 1000000000L / (int) mInfo.refreshRate; // 1 frame + mInfo.presentationDeadlineNanos = 1000000000L / (int) REFRESH_RATE; // 1 frame mInfo.flags = 0; if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index f163555..64bc729 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -583,6 +583,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { private final float mRefreshRate; private final int mFlags; private final String mAddress; + private final Display.Mode mMode; private Surface mSurface; private DisplayDeviceInfo mInfo; @@ -598,6 +599,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { mFlags = flags; mAddress = address; mSurface = surface; + mMode = createMode(width, height, refreshRate); } public void destroyLocked() { @@ -628,8 +630,9 @@ final class WifiDisplayAdapter extends DisplayAdapter { mInfo.uniqueId = getUniqueId(); mInfo.width = mWidth; mInfo.height = mHeight; - mInfo.refreshRate = mRefreshRate; - mInfo.supportedRefreshRates = new float[] { mRefreshRate }; + mInfo.modeId = mMode.getModeId(); + mInfo.defaultModeId = mMode.getModeId(); + mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame mInfo.flags = mFlags; mInfo.type = Display.TYPE_WIFI; diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index ed8519a..0faccc6 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -16,10 +16,12 @@ package com.android.server.fingerprint; +import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; import android.os.Binder; +import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -38,6 +40,7 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver; import static android.Manifest.permission.MANAGE_FINGERPRINT; import static android.Manifest.permission.USE_FINGERPRINT; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -116,6 +119,7 @@ public class FingerprintService extends SystemService { static native int nativeCloseHal(); static native void nativeInit(MessageQueue queue, FingerprintService service); static native long nativeGetAuthenticatorId(); + static native int nativeSetActiveGroup(int gid, byte[] storePath); static final class FpHalMsg { int type; // Type of the message. One of the constants in fingerprint.h @@ -628,6 +632,11 @@ public class FingerprintService extends SystemService { public void onStart() { publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); mHalDeviceId = nativeOpenHal(); + if (mHalDeviceId != 0) { + int userId = ActivityManager.getCurrentUser(); + File path = Environment.getUserSystemDirectory(userId); + nativeSetActiveGroup(0, path.getAbsolutePath().getBytes()); + } if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index e650456..51ba32d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -906,14 +906,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly private void updateArcFeatureStatus(int portId, boolean isConnected) { assertRunOnServiceThread(); + HdmiPortInfo portInfo = mService.getPortInfo(portId); + if (!portInfo.isArcSupported()) { + return; + } HdmiDeviceInfo avr = getAvrDeviceInfo(); if (avr == null) { + if (isConnected) { + // Update the status (since TV may not have seen AVR yet) so + // that ARC can be initiated after discovery. + mArcFeatureEnabled.put(portId, isConnected); + } return; } // HEAC 2.4, HEACT 5-15 // Should not activate ARC if +5V status is false. - HdmiPortInfo portInfo = mService.getPortInfo(portId); - if (avr.getPortId() == portId && portInfo.isArcSupported()) { + if (avr.getPortId() == portId) { changeArcFeatureEnabled(portId, isConnected); } } diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 65949bf..8086461 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -765,8 +765,9 @@ public class MediaSessionService extends SystemService implements Monitor { // If we don't have a media button receiver to fall back on // include non-playing sessions for dispatching UserRecord ur = mUserRecords.get(ActivityManager.getCurrentUser()); - boolean useNotPlayingSessions = ur.mLastMediaButtonReceiver == null - && ur.mRestoredMediaButtonReceiver == null; + boolean useNotPlayingSessions = (ur == null) || + (ur.mLastMediaButtonReceiver == null + && ur.mRestoredMediaButtonReceiver == null); MediaSessionRecord session = mPriorityStack .getDefaultMediaButtonSession(mCurrentUserId, useNotPlayingSessions); if (isVoiceKey(keyEvent.getKeyCode())) { diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java index 28da73c..71d7f19 100644 --- a/services/core/java/com/android/server/notification/CalendarTracker.java +++ b/services/core/java/com/android/server/notification/CalendarTracker.java @@ -16,6 +16,8 @@ package com.android.server.notification; +import static android.service.notification.ZenModeConfig.EventInfo.ANY_CALENDAR; + import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; @@ -150,7 +152,7 @@ public class CalendarTracker { eventId, owner, calendarId)); final boolean meetsTime = time >= begin && time < end; final boolean meetsCalendar = visible - && (filter.calendar == 0 || filter.calendar == calendarId) + && (filter.calendar == ANY_CALENDAR || filter.calendar == calendarId) && availability != Instances.AVAILABILITY_FREE; if (meetsCalendar) { if (DEBUG) Log.d(TAG, " MEETS CALENDAR"); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index b92c734..6f8e3ca 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -189,6 +189,10 @@ abstract public class ManagedServices { } } + public boolean isComponentEnabledForPackage(String pkg) { + return mEnabledServicesPackageNames.contains(pkg); + } + public void onPackagesChanged(boolean queryReplace, String[] pkgList) { if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 25998da..791c1de 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -37,7 +37,6 @@ import android.app.NotificationManager.Policy; import android.app.PendingIntent; import android.app.StatusBarManager; import android.app.usage.UsageEvents; -import android.app.usage.UsageStats; import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -233,7 +232,7 @@ public class NotificationManagerService extends SystemService { new ArrayMap<String, NotificationRecord>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); - private final ArrayMap<String, Policy.Token> mPolicyTokens = new ArrayMap<>(); + private final ArrayMap<String, Boolean> mPolicyAccess = new ArrayMap<>(); // The last key in this list owns the hardware. @@ -899,6 +898,7 @@ public class NotificationManagerService extends SystemService { @Override void onZenModeChanged() { + sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); synchronized(mNotificationList) { updateInterruptionFilterLocked(); } @@ -906,9 +906,12 @@ public class NotificationManagerService extends SystemService { @Override void onPolicyChanged() { - getContext().sendBroadcast( - new Intent(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); + sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); + } + + private void sendRegisteredOnlyBroadcast(String action) { + getContext().sendBroadcast(new Intent(action) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); } }); final File systemDir = new File(Environment.getDataDirectory(), "system"); @@ -1607,6 +1610,19 @@ public class NotificationManagerService extends SystemService { } @Override + public void setInterruptionFilter(String pkg, int filter) throws RemoteException { + enforcePolicyAccess(pkg, "setInterruptionFilter"); + final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); + if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); + final long identity = Binder.clearCallingIdentity(); + try { + mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter"); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public void notifyConditions(String pkg, IConditionProvider provider, Condition[] conditions) { final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); @@ -1641,16 +1657,19 @@ public class NotificationManagerService extends SystemService { message); } - private void enforcePolicyToken(Policy.Token token, String method) { - if (!checkPolicyToken(token)) { - Slog.w(TAG, "Invalid notification policy token calling " + method); - throw new SecurityException("Invalid notification policy token"); + private void enforcePolicyAccess(String pkg, String method) { + if (!checkPolicyAccess(pkg)) { + Slog.w(TAG, "Notification policy access denied calling " + method); + throw new SecurityException("Notification policy access denied"); } } - private boolean checkPolicyToken(Policy.Token token) { - return mPolicyTokens.containsValue(token) - || mListeners.mPolicyTokens.containsValue(token); + private boolean checkPackagePolicyAccess(String pkg) { + return Boolean.TRUE.equals(mPolicyAccess.get(pkg)); + } + + private boolean checkPolicyAccess(String pkg) { + return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg); } @Override @@ -1702,52 +1721,76 @@ public class NotificationManagerService extends SystemService { } @Override - public Policy.Token getPolicyTokenFromListener(INotificationListener listener) { + public void requestNotificationPolicyAccess(String pkg, + INotificationManagerCallback callback) throws RemoteException { + if (callback == null) { + Slog.w(TAG, "requestNotificationPolicyAccess: no callback specified"); + return; + } + if (pkg == null) { + Slog.w(TAG, "requestNotificationPolicyAccess denied: no package specified"); + callback.onPolicyRequestResult(false); + return; + } final long identity = Binder.clearCallingIdentity(); try { - return mListeners.getPolicyToken(listener); + synchronized (mNotificationList) { + // immediately grant for now + mPolicyAccess.put(pkg, true); + if (DBG) Slog.w(TAG, "requestNotificationPolicyAccess granted for " + pkg); + } } finally { Binder.restoreCallingIdentity(identity); } + callback.onPolicyRequestResult(true); } @Override - public void requestNotificationPolicyToken(String pkg, - INotificationManagerCallback callback) throws RemoteException { - if (callback == null) { - Slog.w(TAG, "requestNotificationPolicyToken: no callback specified"); - return; - } - if (pkg == null) { - Slog.w(TAG, "requestNotificationPolicyToken denied: no package specified"); - callback.onPolicyToken(null); - return; - } - Policy.Token token = null; + public boolean isNotificationPolicyAccessGranted(String pkg) { + return checkPolicyAccess(pkg); + } + + @Override + public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { + enforceSystemOrSystemUI("request policy access status for another package"); + return checkPackagePolicyAccess(pkg); + } + + @Override + public String[] getPackagesRequestingNotificationPolicyAccess() + throws RemoteException { + enforceSystemOrSystemUI("request policy access packages"); final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationList) { - token = mPolicyTokens.get(pkg); - if (token == null) { - token = new Policy.Token(new Binder()); - mPolicyTokens.put(pkg, token); + final String[] rt = new String[mPolicyAccess.size()]; + for (int i = 0; i < mPolicyAccess.size(); i++) { + rt[i] = mPolicyAccess.keyAt(i); } - if (DBG) Slog.w(TAG, "requestNotificationPolicyToken granted for " + pkg); + return rt; } } finally { Binder.restoreCallingIdentity(identity); } - callback.onPolicyToken(token); } @Override - public boolean isNotificationPolicyTokenValid(String pkg, Policy.Token token) { - return checkPolicyToken(token); + public void setNotificationPolicyAccessGranted(String pkg, boolean granted) + throws RemoteException { + enforceSystemOrSystemUI("grant notification policy access"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mNotificationList) { + mPolicyAccess.put(pkg, granted); + } + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override - public Policy getNotificationPolicy(Policy.Token token) { - enforcePolicyToken(token, "getNotificationPolicy"); + public Policy getNotificationPolicy(String pkg) { + enforcePolicyAccess(pkg, "getNotificationPolicy"); final long identity = Binder.clearCallingIdentity(); try { return mZenModeHelper.getNotificationPolicy(); @@ -1757,8 +1800,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void setNotificationPolicy(Policy.Token token, Policy policy) { - enforcePolicyToken(token, "setNotificationPolicy"); + public void setNotificationPolicy(String pkg, Policy policy) { + enforcePolicyAccess(pkg, "setNotificationPolicy"); final long identity = Binder.clearCallingIdentity(); try { mZenModeHelper.setNotificationPolicy(policy); @@ -1881,11 +1924,9 @@ public class NotificationManagerService extends SystemService { pw.print(listener.component); } pw.println(')'); - pw.print(" mPolicyTokens.keys: "); - pw.println(TextUtils.join(",", mPolicyTokens.keySet())); - pw.print(" mListeners.mPolicyTokens.keys: "); - pw.println(TextUtils.join(",", mListeners.mPolicyTokens.keySet())); } + pw.println("\n Policy access:"); + pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); pw.println("\n Condition providers:"); mConditionProviders.dump(pw, filter); @@ -3138,18 +3179,12 @@ public class NotificationManagerService extends SystemService { public class NotificationListeners extends ManagedServices { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); - private final ArrayMap<ComponentName, Policy.Token> mPolicyTokens = new ArrayMap<>(); private boolean mNotificationGroupsDesired; public NotificationListeners() { super(getContext(), mHandler, mNotificationList, mUserProfiles); } - public Policy.Token getPolicyToken(INotificationListener listener) { - final ManagedServiceInfo info = checkServiceTokenLocked(listener); - return info == null ? null : mPolicyTokens.get(info.component); - } - @Override protected Config getConfig() { Config c = new Config(); @@ -3174,7 +3209,6 @@ public class NotificationManagerService extends SystemService { synchronized (mNotificationList) { updateNotificationGroupsDesiredLocked(); update = makeRankingUpdateLocked(info); - mPolicyTokens.put(info.component, new Policy.Token(new Binder())); } try { listener.onListenerConnected(update); @@ -3191,7 +3225,6 @@ public class NotificationManagerService extends SystemService { } mLightTrimListeners.remove(removed); updateNotificationGroupsDesiredLocked(); - mPolicyTokens.remove(removed.component); } public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index e97def8..aeb6b78 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -22,6 +22,7 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import android.app.AppOpsManager; +import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.ContentResolver; @@ -42,6 +43,7 @@ import android.provider.Settings.Global; import android.service.notification.IConditionListener; import android.service.notification.NotificationListenerService; import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeConfig.EventInfo; import android.service.notification.ZenModeConfig.ScheduleInfo; import android.service.notification.ZenModeConfig.ZenRule; import android.util.ArraySet; @@ -90,6 +92,7 @@ public class ZenModeHelper { mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mDefaultConfig = readDefaultConfig(context.getResources()); appendDefaultScheduleRules(mDefaultConfig); + appendDefaultEventRules(mDefaultConfig); mConfig = mDefaultConfig; mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe(); @@ -142,11 +145,11 @@ public class ZenModeHelper { } public int getZenModeListenerInterruptionFilter() { - return getZenModeListenerInterruptionFilter(mZenMode); + return NotificationManager.zenModeToInterruptionFilter(mZenMode); } - public void requestFromListener(ComponentName name, int interruptionFilter) { - final int newZen = zenModeFromListenerInterruptionFilter(interruptionFilter, -1); + public void requestFromListener(ComponentName name, int filter) { + final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); if (newZen != -1) { setManualZenMode(newZen, null, "listener:" + (name != null ? name.flattenToShortString() : null)); @@ -393,37 +396,6 @@ public class ZenModeHelper { } } - private static int getZenModeListenerInterruptionFilter(int zen) { - switch (zen) { - case Global.ZEN_MODE_OFF: - return NotificationListenerService.INTERRUPTION_FILTER_ALL; - case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: - return NotificationListenerService.INTERRUPTION_FILTER_PRIORITY; - case Global.ZEN_MODE_ALARMS: - return NotificationListenerService.INTERRUPTION_FILTER_ALARMS; - case Global.ZEN_MODE_NO_INTERRUPTIONS: - return NotificationListenerService.INTERRUPTION_FILTER_NONE; - default: - return 0; - } - } - - private static int zenModeFromListenerInterruptionFilter(int listenerInterruptionFilter, - int defValue) { - switch (listenerInterruptionFilter) { - case NotificationListenerService.INTERRUPTION_FILTER_ALL: - return Global.ZEN_MODE_OFF; - case NotificationListenerService.INTERRUPTION_FILTER_PRIORITY: - return Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; - case NotificationListenerService.INTERRUPTION_FILTER_ALARMS: - return Global.ZEN_MODE_ALARMS; - case NotificationListenerService.INTERRUPTION_FILTER_NONE: - return Global.ZEN_MODE_NO_INTERRUPTIONS; - default: - return defValue; - } - } - private ZenModeConfig readDefaultConfig(Resources resources) { XmlResourceParser parser = null; try { @@ -469,6 +441,20 @@ public class ZenModeHelper { config.automaticRules.put(config.newRuleId(), rule2); } + private void appendDefaultEventRules(ZenModeConfig config) { + if (config == null) return; + + final EventInfo events = new EventInfo(); + events.calendar = EventInfo.ANY_CALENDAR; + events.reply = EventInfo.REPLY_YES_OR_MAYBE; + final ZenRule rule = new ZenRule(); + rule.enabled = false; + rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name); + rule.conditionId = ZenModeConfig.toEventConditionId(events); + rule.zenMode = Global.ZEN_MODE_ALARMS; + config.automaticRules.put(config.newRuleId(), rule); + } + private static int zenSeverity(int zen) { switch (zen) { case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1; @@ -511,6 +497,7 @@ public class ZenModeHelper { Log.i(TAG, "No existing V1 downtime found, generating default schedules"); appendDefaultScheduleRules(rt); } + appendDefaultEventRules(rt); return rt; } }; diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java index 30f8b37..18407c9 100644 --- a/services/core/java/com/android/server/pm/BasePermission.java +++ b/services/core/java/com/android/server/pm/BasePermission.java @@ -20,8 +20,6 @@ import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; import android.os.UserHandle; -import com.android.internal.util.ArrayUtils; - final class BasePermission { final static int TYPE_NORMAL = 0; diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index a42e4e7..b505f7e 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -31,7 +31,6 @@ import java.util.ArrayList; import java.util.List; import dalvik.system.DexFile; -import dalvik.system.StaleDexCacheError; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; @@ -112,61 +111,60 @@ final class PackageDexOptimizer { } for (String path : paths) { - try { - final int dexoptNeeded; - if (forceDex) { - dexoptNeeded = DexFile.DEX2OAT_NEEDED; - } else { - dexoptNeeded = DexFile.getDexOptNeeded(path, - pkg.packageName, dexCodeInstructionSet, defer); + final int dexoptNeeded; + if (forceDex) { + dexoptNeeded = DexFile.DEX2OAT_NEEDED; + } else { + try { + dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName, + dexCodeInstructionSet, defer); + } catch (IOException ioe) { + Slog.w(TAG, "IOException reading apk: " + path, ioe); + return DEX_OPT_FAILED; } + } - if (!forceDex && defer && dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { - // We're deciding to defer a needed dexopt. Don't bother dexopting for other - // paths and instruction sets. We'll deal with them all together when we process - // our list of deferred dexopts. - addPackageForDeferredDexopt(pkg); - return DEX_OPT_DEFERRED; - } + if (!forceDex && defer && dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { + // We're deciding to defer a needed dexopt. Don't bother dexopting for other + // paths and instruction sets. We'll deal with them all together when we process + // our list of deferred dexopts. + addPackageForDeferredDexopt(pkg); + return DEX_OPT_DEFERRED; + } - if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { - final String dexoptType; - String oatDir = null; - if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) { - dexoptType = "dex2oat"; + if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { + final String dexoptType; + String oatDir = null; + if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) { + dexoptType = "dex2oat"; + try { oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet); - } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) { - dexoptType = "patchoat"; - } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) { - dexoptType = "self patchoat"; - } else { - throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded); - } - Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg=" - + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet - + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable - + " oatDir = " + oatDir); - final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); - final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid, - !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet, - dexoptNeeded, vmSafeMode, debuggable, oatDir); - if (ret < 0) { + } catch (IOException ioe) { + Slog.w(TAG, "Unable to create oatDir for package: " + pkg.packageName); return DEX_OPT_FAILED; } + } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) { + dexoptType = "patchoat"; + } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) { + dexoptType = "self patchoat"; + } else { + throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded); + } + + Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg=" + + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet + + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable + + " oatDir = " + oatDir); + final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid, + !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet, + dexoptNeeded, vmSafeMode, debuggable, oatDir); + + // Dex2oat might fail due to compiler / verifier errors. We soldier on + // regardless, and attempt to interpret the app as a safety net. + if (ret == 0) { performedDexOpt = true; } - } catch (FileNotFoundException e) { - Slog.w(TAG, "Apk not found for dexopt: " + path); - return DEX_OPT_FAILED; - } catch (IOException e) { - Slog.w(TAG, "IOException reading apk: " + path, e); - return DEX_OPT_FAILED; - } catch (StaleDexCacheError e) { - Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e); - return DEX_OPT_FAILED; - } catch (Exception e) { - Slog.w(TAG, "Exception when doing dexopt : ", e); - return DEX_OPT_FAILED; } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a120c1f..477af72 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -206,6 +206,7 @@ import com.android.server.ServiceThread; import com.android.server.SystemConfig; import com.android.server.Watchdog; import com.android.server.pm.Settings.DatabaseVersion; +import com.android.server.pm.PermissionsState.PermissionState; import com.android.server.storage.DeviceStorageMonitorInternal; import org.xmlpull.v1.XmlPullParser; @@ -304,6 +305,8 @@ public class PackageManagerService extends IPackageManager.Stub { static final int REMOVE_CHATTY = 1<<16; + private static final int[] EMPTY_INT_ARRAY = new int[0]; + /** * Timeout (in milliseconds) after which the watchdog should declare that * our handler thread is wedged. The usual default for such things is one @@ -3139,18 +3142,26 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private static void enforceOnlySystemUpdatesPermissionPolicyFlags(int flagMask, int flagValues) { + if (((flagMask & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0 + || (flagValues & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) + && getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Only the system can modify policy flags"); + } + } + @Override - public void grantPermission(String packageName, String name, int userId) { + public void grantRuntimePermission(String packageName, String name, int userId) { if (!sUserManager.exists(userId)) { return; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, - "grantPermission"); + "grantRuntimePermission"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, - "grantPermission"); + "grantRuntimePermission"); boolean gidsChanged = false; final SettingBase sb; @@ -3197,17 +3208,17 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public void revokePermission(String packageName, String name, int userId) { + public void revokeRuntimePermission(String packageName, String name, int userId) { if (!sUserManager.exists(userId)) { return; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, - "revokePermission"); + "revokeRuntimePermission"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, - "revokePermission"); + "revokeRuntimePermission"); final SettingBase sb; @@ -3236,7 +3247,7 @@ public class PackageManagerService extends IPackageManager.Stub { return; } - // Critical, after this call all should never have the permission. + // Critical, after this call app should never have the permission. mSettings.writeRuntimePermissionsForUserLPr(userId, true); } @@ -3244,6 +3255,86 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override + public int getPermissionFlags(String name, String packageName, int userId) { + if (!sUserManager.exists(userId)) { + return 0; + } + + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, + "getPermissionFlags"); + + enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, + "getPermissionFlags"); + + synchronized (mPackages) { + final PackageParser.Package pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + + final BasePermission bp = mSettings.mPermissions.get(name); + if (bp == null) { + throw new IllegalArgumentException("Unknown permission: " + name); + } + + SettingBase sb = (SettingBase) pkg.mExtras; + if (sb == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + + PermissionsState permissionsState = sb.getPermissionsState(); + return permissionsState.getPermissionFlags(name, userId); + } + } + + @Override + public void updatePermissionFlags(String name, String packageName, int flagMask, + int flagValues, int userId) { + if (!sUserManager.exists(userId)) { + return; + } + + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, + "updatePermissionFlags"); + + enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, + "updatePermissionFlags"); + + enforceOnlySystemUpdatesPermissionPolicyFlags(flagMask, flagValues); + + synchronized (mPackages) { + final PackageParser.Package pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + + final BasePermission bp = mSettings.mPermissions.get(name); + if (bp == null) { + throw new IllegalArgumentException("Unknown permission: " + name); + } + + SettingBase sb = (SettingBase) pkg.mExtras; + if (sb == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + + PermissionsState permissionsState = sb.getPermissionsState(); + + if (permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues)) { + // Install and runtime permissions are stored in different places, + // so figure out what permission changed and persist the change. + if (permissionsState.getInstallPermissionState(name) != null) { + scheduleWriteSettingsLocked(); + } else if (permissionsState.getRuntimePermissionState(name, userId) != null) { + mSettings.writeRuntimePermissionsForUserLPr(userId, false); + } + } + } + } + + @Override public boolean isProtectedBroadcast(String actionName) { synchronized (mPackages) { return mProtectedBroadcasts.contains(actionName); @@ -7530,8 +7621,8 @@ public class PackageManagerService extends IPackageManager.Stub { final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); - int[] upgradeUserIds = PermissionsState.USERS_NONE; - int[] changedRuntimePermissionUserIds = PermissionsState.USERS_NONE; + int[] upgradeUserIds = EMPTY_INT_ARRAY; + int[] changedRuntimePermissionUserIds = EMPTY_INT_ARRAY; boolean changedInstallPermission = false; @@ -7657,11 +7748,18 @@ public class PackageManagerService extends IPackageManager.Stub { // Grant previously granted runtime permissions. for (int userId : UserManagerService.getInstance().getUserIds()) { if (origPermissions.hasRuntimePermission(bp.name, userId)) { + PermissionState permissionState = origPermissions + .getRuntimePermissionState(bp.name, userId); + final int flags = permissionState.getFlags(); if (permissionsState.grantRuntimePermission(bp, userId) == PermissionsState.PERMISSION_OPERATION_FAILURE) { // If we cannot put the permission as it was, we have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); + } else { + // Propagate the permission flags. + permissionsState.updatePermissionFlags(bp, userId, + flags, flags); } } } @@ -7669,13 +7767,28 @@ public class PackageManagerService extends IPackageManager.Stub { case GRANT_UPGRADE: { // Grant runtime permissions for a previously held install permission. - permissionsState.revokeInstallPermission(bp); - for (int userId : upgradeUserIds) { - if (permissionsState.grantRuntimePermission(bp, userId) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { - // If we granted the permission, we have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); + PermissionState permissionState = origPermissions + .getInstallPermissionState(bp.name); + final int flags = permissionState != null ? permissionState.getFlags() : 0; + + origPermissions.revokeInstallPermission(bp); + // We will be transferring the permission flags, so clear them. + origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL, + PackageManager.MASK_PERMISSION_FLAGS, 0); + + // If the permission is not to be promoted to runtime we ignore it and + // also its other flags as they are not applicable to install permissions. + if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) { + for (int userId : upgradeUserIds) { + if (permissionsState.grantRuntimePermission(bp, userId) != + PermissionsState.PERMISSION_OPERATION_FAILURE) { + // Transfer the permission flags. + permissionsState.updatePermissionFlags(bp, userId, + flags, flags); + // If we granted the permission, we have to write. + changedRuntimePermissionUserIds = ArrayUtils.appendInt( + changedRuntimePermissionUserIds, userId); + } } } } break; @@ -7692,6 +7805,9 @@ public class PackageManagerService extends IPackageManager.Stub { } else { if (permissionsState.revokeInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { + // Also drop the permission flags. + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + PackageManager.MASK_PERMISSION_FLAGS, 0); changedInstallPermission = true; Slog.i(TAG, "Un-granting permission " + perm + " from package " + pkg.packageName @@ -9101,7 +9217,9 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { result = mSettings.updateIntentFilterVerificationStatusLPw(packageName, status, userId); } - scheduleWritePackageRestrictionsLocked(userId); + if (result) { + scheduleWritePackageRestrictionsLocked(userId); + } return result; } @@ -9138,9 +9256,11 @@ public class PackageManagerService extends IPackageManager.Stub { public boolean setDefaultBrowserPackageName(String packageName, int userId) { synchronized (mPackages) { boolean result = mSettings.setDefaultBrowserPackageNameLPr(packageName, userId); - result |= updateIntentVerificationStatus(packageName, - PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, - UserHandle.myUserId()); + if (packageName != null) { + result |= updateIntentVerificationStatus(packageName, + PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, + UserHandle.myUserId()); + } return result; } } @@ -11854,6 +11974,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (deletedPs != null) { if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) { clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL); + clearDefaultBrowserIfNeeded(packageName); if (outInfo != null) { mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); outInfo.removedAppId = mSettings.removePackageLPw(packageName); @@ -12388,7 +12509,7 @@ public class PackageManagerService extends IPackageManager.Stub { succeded = deleteApplicationCacheFilesLI(packageName, userId); } clearExternalStorageDataSync(packageName, userId, false); - if(observer != null) { + if (observer != null) { try { observer.onRemoveCompleted(packageName, succeded); } catch (RemoteException e) { @@ -12757,6 +12878,17 @@ public class PackageManagerService extends IPackageManager.Stub { } } + + void clearDefaultBrowserIfNeeded(String packageName) { + for (int oneUserId : sUserManager.getUserIds()) { + String defaultBrowserPackageName = getDefaultBrowserPackageName(oneUserId); + if (TextUtils.isEmpty(defaultBrowserPackageName)) continue; + if (packageName.equals(defaultBrowserPackageName)) { + setDefaultBrowserPackageName(null, oneUserId); + } + } + } + @Override public void resetPreferredActivities(int userId) { /* TODO: Actually use userId. Why is it being passed in? */ diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java index 3749957..171a50d 100644 --- a/services/core/java/com/android/server/pm/PermissionsState.java +++ b/services/core/java/com/android/server/pm/PermissionsState.java @@ -20,10 +20,13 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.SparseArray; import com.android.internal.util.ArrayUtils; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Set; /** @@ -55,15 +58,8 @@ public final class PermissionsState { /** The permission operation failed. */ public static final int PERMISSION_OPERATION_FAILURE = 3; - public static final int[] USERS_ALL = {UserHandle.USER_ALL}; - - public static final int[] USERS_NONE = {}; - private static final int[] NO_GIDS = {}; - private static final int FLAG_INSTALL_PERMISSIONS = 1 << 0; - private static final int FLAG_RUNTIME_PERMISSIONS = 1 << 1; - private ArrayMap<String, PermissionData> mPermissions; private int[] mGlobalGids = NO_GIDS; @@ -147,14 +143,16 @@ public final class PermissionsState { } /** - * Grant a runtime permission. + * Grant a runtime permission for a given device user. * * @param permission The permission to grant. + * @param userId The device user id. * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link * #PERMISSION_OPERATION_FAILURE}. */ public int grantRuntimePermission(BasePermission permission, int userId) { + enforceValidUserId(userId); if (userId == UserHandle.USER_ALL) { return PERMISSION_OPERATION_FAILURE; } @@ -162,15 +160,18 @@ public final class PermissionsState { } /** - * Revoke a runtime permission for a given device user. + * Revoke a runtime permission for a given device user. * * @param permission The permission to revoke. * @param userId The device user id. * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link * #PERMISSION_OPERATION_FAILURE}. + * + * @see android.content.pm.PackageManager.PermissionFlags */ public int revokeRuntimePermission(BasePermission permission, int userId) { + enforceValidUserId(userId); if (userId == UserHandle.USER_ALL) { return PERMISSION_OPERATION_FAILURE; } @@ -178,17 +179,6 @@ public final class PermissionsState { } /** - * Gets whether this state has a given permission, regardless if - * it is install time or runtime one. - * - * @param name The permission name. - * @return Whether this state has the permission. - */ - public boolean hasPermission(String name) { - return mPermissions != null && mPermissions.get(name) != null; - } - - /** * Gets whether this state has a given runtime permission for a * given device user id. * @@ -197,6 +187,7 @@ public final class PermissionsState { * @return Whether this state has the permission. */ public boolean hasRuntimePermission(String name, int userId) { + enforceValidUserId(userId); return !hasInstallPermission(name) && hasPermission(name, userId); } @@ -211,36 +202,6 @@ public final class PermissionsState { } /** - * Revokes a permission for all users regardless if it is an install or - * a runtime permission. - * - * @param permission The permission to revoke. - * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, - * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link - * #PERMISSION_OPERATION_FAILURE}. - */ - public int revokePermission(BasePermission permission) { - if (!hasPermission(permission.name)) { - return PERMISSION_OPERATION_FAILURE; - } - - int result = PERMISSION_OPERATION_SUCCESS; - - PermissionData permissionData = mPermissions.get(permission.name); - for (int userId : permissionData.getUserIds()) { - if (revokePermission(permission, userId) - == PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { - result = PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; - break; - } - } - - mPermissions.remove(permission.name); - - return result; - } - - /** * Gets whether the state has a given permission for the specified * user, regardless if this is an install or a runtime permission. * @@ -256,49 +217,133 @@ public final class PermissionsState { } PermissionData permissionData = mPermissions.get(name); - return permissionData != null && permissionData.hasUserId(userId); + return permissionData != null && permissionData.isGranted(userId); } /** - * Gets all permissions regardless if they are install or runtime. + * Gets all permissions for a given device user id regardless if they + * are install time or runtime permissions. * + * @param userId The device user id. * @return The permissions or an empty set. */ - public Set<String> getPermissions() { - if (mPermissions != null) { - return mPermissions.keySet(); + public Set<String> getPermissions(int userId) { + enforceValidUserId(userId); + + if (mPermissions == null) { + return Collections.emptySet(); } - return Collections.emptySet(); + Set<String> permissions = new ArraySet<>(); + + final int permissionCount = mPermissions.size(); + for (int i = 0; i < permissionCount; i++) { + String permission = mPermissions.keyAt(i); + + if (hasInstallPermission(permission)) { + permissions.add(permission); + } + + if (userId != UserHandle.USER_ALL) { + if (hasRuntimePermission(permission, userId)) { + permissions.add(permission); + } + } + } + + return permissions; } /** - * Gets all permissions for a given device user id regardless if they - * are install time or runtime permissions. + * Gets the state for an install permission or null if no such. * + * @param name The permission name. + * @return The permission state. + */ + public PermissionState getInstallPermissionState(String name) { + return getPermissionState(name, UserHandle.USER_ALL); + } + + /** + * Gets the state for a runtime permission or null if no such. + * + * @param name The permission name. * @param userId The device user id. - * @return The permissions or an empty set. + * @return The permission state. */ - public Set<String> getPermissions(int userId) { - return getPermissionsInternal(FLAG_INSTALL_PERMISSIONS | FLAG_RUNTIME_PERMISSIONS, userId); + public PermissionState getRuntimePermissionState(String name, int userId) { + enforceValidUserId(userId); + return getPermissionState(name, userId); } /** - * Gets all runtime permissions. + * Gets all install permission states. * - * @return The permissions or an empty set. + * @return The permission states or an empty set. */ - public Set<String> getRuntimePermissions(int userId) { - return getPermissionsInternal(FLAG_RUNTIME_PERMISSIONS, userId); + public List<PermissionState> getInstallPermissionStates() { + return getPermissionStatesInternal(UserHandle.USER_ALL); } /** - * Gets all install permissions. + * Gets all runtime permission states. * - * @return The permissions or an empty set. + * @return The permission states or an empty set. + */ + public List<PermissionState> getRuntimePermissionStates(int userId) { + enforceValidUserId(userId); + return getPermissionStatesInternal(userId); + } + + /** + * Gets the flags for a permission regardless if it is install or + * runtime permission. + * + * @param name The permission name. + * @return The permission state or null if no such. */ - public Set<String> getInstallPermissions() { - return getPermissionsInternal(FLAG_INSTALL_PERMISSIONS, UserHandle.USER_ALL); + public int getPermissionFlags(String name, int userId) { + PermissionState installPermState = getInstallPermissionState(name); + if (installPermState != null) { + return installPermState.getFlags(); + } + PermissionState runtimePermState = getRuntimePermissionState(name, userId); + if (runtimePermState != null) { + return runtimePermState.getFlags(); + } + return 0; + } + + /** + * Update the flags associated with a given permission. + * @param permission The permission whose flags to update. + * @param userId The user for which to update. + * @param flagMask Mask for which flags to change. + * @param flagValues New values for the mask flags. + * @return Whether the permission flags changed. + */ + public boolean updatePermissionFlags(BasePermission permission, int userId, + int flagMask, int flagValues) { + enforceValidUserId(userId); + + final boolean mayChangeFlags = flagValues != 0 || flagMask != 0; + + if (mPermissions == null) { + if (!mayChangeFlags) { + return false; + } + ensurePermissionData(permission); + } + + PermissionData permissionData = mPermissions.get(permission.name); + if (permissionData == null) { + if (!mayChangeFlags) { + return false; + } + permissionData = ensurePermissionData(permission); + } + + return permissionData.updateFlags(userId, flagMask, flagValues); } /** @@ -357,36 +402,37 @@ public final class PermissionsState { mPermissions = null; } - private Set<String> getPermissionsInternal(int flags, int userId) { - enforceValidUserId(userId); - + private PermissionState getPermissionState(String name, int userId) { if (mPermissions == null) { - return Collections.emptySet(); + return null; } + PermissionData permissionData = mPermissions.get(name); + if (permissionData == null) { + return null; + } + return permissionData.getPermissionState(userId); + } - if (userId == UserHandle.USER_ALL) { - flags = FLAG_INSTALL_PERMISSIONS; + private List<PermissionState> getPermissionStatesInternal(int userId) { + enforceValidUserId(userId); + + if (mPermissions == null) { + return Collections.emptyList(); } - Set<String> permissions = new ArraySet<>(); + List<PermissionState> permissionStates = new ArrayList<>(); final int permissionCount = mPermissions.size(); for (int i = 0; i < permissionCount; i++) { - String permission = mPermissions.keyAt(i); + PermissionData permissionData = mPermissions.valueAt(i); - if ((flags & FLAG_INSTALL_PERMISSIONS) != 0) { - if (hasInstallPermission(permission)) { - permissions.add(permission); - } - } - if ((flags & FLAG_RUNTIME_PERMISSIONS) != 0) { - if (hasRuntimePermission(permission, userId)) { - permissions.add(permission); - } + PermissionState permissionState = permissionData.getPermissionState(userId); + if (permissionState != null) { + permissionStates.add(permissionState); } } - return permissions; + return permissionStates; } private int grantPermission(BasePermission permission, int userId) { @@ -397,17 +443,9 @@ public final class PermissionsState { final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId)); final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS; - if (mPermissions == null) { - mPermissions = new ArrayMap<>(); - } - - PermissionData permissionData = mPermissions.get(permission.name); - if (permissionData == null) { - permissionData = new PermissionData(permission); - mPermissions.put(permission.name, permissionData); - } + PermissionData permissionData = ensurePermissionData(permission); - if (!permissionData.addUserId(userId)) { + if (!permissionData.grant(userId)) { return PERMISSION_OPERATION_FAILURE; } @@ -431,16 +469,12 @@ public final class PermissionsState { PermissionData permissionData = mPermissions.get(permission.name); - if (!permissionData.removeUserId(userId)) { + if (!permissionData.revoke(userId)) { return PERMISSION_OPERATION_FAILURE; } - if (permissionData.getUserIds() == USERS_NONE) { - mPermissions.remove(permission.name); - } - - if (mPermissions.isEmpty()) { - mPermissions = null; + if (permissionData.isDefault()) { + ensureNoPermissionData(permission.name); } if (hasGids) { @@ -468,9 +502,31 @@ public final class PermissionsState { } } + private PermissionData ensurePermissionData(BasePermission permission) { + if (mPermissions == null) { + mPermissions = new ArrayMap<>(); + } + PermissionData permissionData = mPermissions.get(permission.name); + if (permissionData == null) { + permissionData = new PermissionData(permission); + mPermissions.put(permission.name, permissionData); + } + return permissionData; + } + + private void ensureNoPermissionData(String name) { + if (mPermissions == null) { + return; + } + mPermissions.remove(name); + if (mPermissions.isEmpty()) { + mPermissions = null; + } + } + private static final class PermissionData { private final BasePermission mPerm; - private int[] mUserIds = USERS_NONE; + private SparseArray<PermissionState> mUserStates = new SparseArray<>(); public PermissionData(BasePermission perm) { mPerm = perm; @@ -478,11 +534,11 @@ public final class PermissionsState { public PermissionData(PermissionData other) { this(other.mPerm); - - if (other.mUserIds == USERS_ALL || other.mUserIds == USERS_NONE) { - mUserIds = other.mUserIds; - } else { - mUserIds = Arrays.copyOf(other.mUserIds, other.mUserIds.length); + final int otherStateCount = other.mUserStates.size(); + for (int i = 0; i < otherStateCount; i++) { + final int otherUserId = other.mUserStates.keyAt(i); + PermissionState otherState = other.mUserStates.valueAt(i); + mUserStates.put(otherUserId, new PermissionState(otherState)); } } @@ -490,53 +546,146 @@ public final class PermissionsState { return mPerm.computeGids(userId); } - public int[] getUserIds() { - return mUserIds; - } - - public boolean hasUserId(int userId) { - if (mUserIds == USERS_ALL) { - return true; + public boolean isGranted(int userId) { + if (isInstallPermission()) { + userId = UserHandle.USER_ALL; } - if (userId != UserHandle.USER_ALL) { - return ArrayUtils.contains(mUserIds, userId); + PermissionState userState = mUserStates.get(userId); + if (userState == null) { + return false; } - return false; + return userState.mGranted; } - public boolean addUserId(int userId) { - if (hasUserId(userId)) { + public boolean grant(int userId) { + if (!isCompatibleUserId(userId)) { return false; } - if (userId == UserHandle.USER_ALL) { - mUserIds = USERS_ALL; - return true; + if (isGranted(userId)) { + return false; } - mUserIds = ArrayUtils.appendInt(mUserIds, userId); + PermissionState userState = mUserStates.get(userId); + if (userState == null) { + userState = new PermissionState(mPerm.name); + mUserStates.put(userId, userState); + } + + userState.mGranted = true; return true; } - public boolean removeUserId(int userId) { - if (!hasUserId(userId)) { + public boolean revoke(int userId) { + if (!isCompatibleUserId(userId)) { return false; } - if (mUserIds == USERS_ALL) { - mUserIds = UserManagerService.getInstance().getUserIds(); + if (!isGranted(userId)) { + return false; } - mUserIds = ArrayUtils.removeInt(mUserIds, userId); + PermissionState userState = mUserStates.get(userId); + userState.mGranted = false; - if (mUserIds.length == 0) { - mUserIds = USERS_NONE; + if (userState.isDefault()) { + mUserStates.remove(userId); } return true; } + + public PermissionState getPermissionState(int userId) { + return mUserStates.get(userId); + } + + public int getFlags(int userId) { + PermissionState userState = mUserStates.get(userId); + if (userState != null) { + return userState.mFlags; + } + return 0; + } + + public boolean isDefault() { + return mUserStates.size() <= 0; + } + + public static boolean isInstallPermissionKey(int userId) { + return userId == UserHandle.USER_ALL; + } + + public boolean updateFlags(int userId, int flagMask, int flagValues) { + if (isInstallPermission()) { + userId = UserHandle.USER_ALL; + } + + if (!isCompatibleUserId(userId)) { + return false; + } + + final int newFlags = flagValues & flagMask; + + PermissionState userState = mUserStates.get(userId); + if (userState != null) { + final int oldFlags = userState.mFlags; + userState.mFlags = (userState.mFlags & ~flagMask) | newFlags; + if (userState.isDefault()) { + mUserStates.remove(userId); + } + return userState.mFlags != oldFlags; + } else if (newFlags != 0) { + userState = new PermissionState(mPerm.name); + userState.mFlags = newFlags; + mUserStates.put(userId, userState); + return true; + } + + return false; + } + + private boolean isCompatibleUserId(int userId) { + return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId)); + } + + private boolean isInstallPermission() { + return mUserStates.size() == 1 + && mUserStates.get(UserHandle.USER_ALL) != null; + } + } + + public static final class PermissionState { + private final String mName; + private boolean mGranted; + private int mFlags; + + public PermissionState(String name) { + mName = name; + } + + public PermissionState(PermissionState other) { + mName = other.mName; + mGranted = other.mGranted; + mFlags = other.mFlags; + } + + public boolean isDefault() { + return !mGranted && mFlags == 0; + } + + public String getName() { + return mName; + } + + public boolean isGranted() { + return mGranted; + } + + public int getFlags() { + return mFlags; + } } } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index 0c7f79d..c35258a 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -21,11 +21,13 @@ import android.content.pm.ApplicationInfo; import java.util.Arrays; abstract class SettingBase { + private static final int[] USERS_NONE = new int[0]; + int pkgFlags; int pkgPrivateFlags; protected final PermissionsState mPermissionsState; - private int[] mPermissionsUpdatedForUserIds = PermissionsState.USERS_NONE; + private int[] mPermissionsUpdatedForUserIds = USERS_NONE; SettingBase(int pkgFlags, int pkgPrivateFlags) { setFlags(pkgFlags); @@ -53,7 +55,7 @@ abstract class SettingBase { return; } - if (userIds == PermissionsState.USERS_NONE || userIds == PermissionsState.USERS_ALL) { + if (userIds == USERS_NONE) { mPermissionsUpdatedForUserIds = userIds; } else { mPermissionsUpdatedForUserIds = Arrays.copyOf(userIds, userIds.length); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index fd70ce1..2e9656a 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -60,6 +60,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.backup.PreferredActivityBackupHelper; import com.android.server.pm.PackageManagerService.DumpState; +import com.android.server.pm.PermissionsState.PermissionState; import java.io.FileNotFoundException; import java.util.Collection; @@ -178,6 +179,8 @@ final class Settings { private static final String ATTR_CODE = "code"; private static final String ATTR_NOT_LAUNCHED = "nl"; private static final String ATTR_ENABLED = "enabled"; + private static final String ATTR_GRANTED = "granted"; + private static final String ATTR_FLAGS = "flags"; private static final String ATTR_ENABLED_CALLER = "enabledCaller"; private static final String ATTR_STOPPED = "stopped"; // Legacy, here for reading older versions of the package-restrictions. @@ -820,14 +823,20 @@ final class Settings { } if (!used) { + PermissionsState permissionsState = sus.getPermissionsState(); + // Try to revoke as an install permission which is for all users. - if (sus.getPermissionsState().revokeInstallPermission(bp) == + // The package is gone - no need to keep flags for applying policy. + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS, 0); + + if (permissionsState.revokeInstallPermission(bp) == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { return UserHandle.USER_ALL; } // Try to revoke as an install permission which is per user. - if (sus.getPermissionsState().revokeRuntimePermission(bp, userId) == + if (permissionsState.revokeRuntimePermission(bp, userId) == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { return userId; } @@ -1724,10 +1733,32 @@ final class Settings { continue; } - if (permissionsState.grantInstallPermission(bp) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - Slog.w(PackageManagerService.TAG, "Permission already added: " + name); - XmlUtils.skipCurrentTag(parser); + String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED); + final boolean granted = grantedStr == null + || Boolean.parseBoolean(grantedStr); + + String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS); + final int flags = (flagsStr != null) + ? Integer.parseInt(flagsStr, 16) : 0; + + if (granted) { + if (permissionsState.grantInstallPermission(bp) == + PermissionsState.PERMISSION_OPERATION_FAILURE) { + Slog.w(PackageManagerService.TAG, "Permission already added: " + name); + XmlUtils.skipCurrentTag(parser); + } else { + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + PackageManager.MASK_PERMISSION_FLAGS, flags); + } + } else { + if (permissionsState.revokeInstallPermission(bp) == + PermissionsState.PERMISSION_OPERATION_FAILURE) { + Slog.w(PackageManagerService.TAG, "Permission already added: " + name); + XmlUtils.skipCurrentTag(parser); + } else { + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + PackageManager.MASK_PERMISSION_FLAGS, flags); + } } } else { Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: " @@ -1737,17 +1768,19 @@ final class Settings { } } - void writePermissionsLPr(XmlSerializer serializer, Set<String> permissions) + void writePermissionsLPr(XmlSerializer serializer, List<PermissionState> permissionStates) throws IOException { - if (permissions.isEmpty()) { + if (permissionStates.isEmpty()) { return; } serializer.startTag(null, TAG_PERMISSIONS); - for (String permission : permissions) { + for (PermissionState permissionState : permissionStates) { serializer.startTag(null, TAG_ITEM); - serializer.attribute(null, ATTR_NAME, permission); + serializer.attribute(null, ATTR_NAME, permissionState.getName()); + serializer.attribute(null, ATTR_GRANTED, String.valueOf(permissionState.isGranted())); + serializer.attribute(null, ATTR_FLAGS, Integer.toHexString(permissionState.getFlags())); serializer.endTag(null, TAG_ITEM); } @@ -1945,7 +1978,8 @@ final class Settings { serializer.attribute(null, "userId", Integer.toString(usr.userId)); usr.signatures.writeXml(serializer, "sigs", mPastSignatures); - writePermissionsLPr(serializer, usr.getPermissionsState().getInstallPermissions()); + writePermissionsLPr(serializer, usr.getPermissionsState() + .getInstallPermissionStates()); serializer.endTag(null, "shared-user"); } @@ -2120,7 +2154,8 @@ final class Settings { // If this is a shared user, the permissions will be written there. if (pkg.sharedUser == null) { - writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions()); + writePermissionsLPr(serializer, pkg.getPermissionsState() + .getInstallPermissionStates()); } serializer.endTag(null, "updated-package"); @@ -2175,9 +2210,9 @@ final class Settings { serializer.attribute(null, "volumeUuid", pkg.volumeUuid); } pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); - if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { - writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions()); - } + + writePermissionsLPr(serializer, pkg.getPermissionsState() + .getInstallPermissionStates()); writeSigningKeySetLPr(serializer, pkg.keySetData); writeUpgradeKeySetsLPr(serializer, pkg.keySetData); @@ -3922,7 +3957,7 @@ final class Settings { PermissionsState permissionsState = ps.getPermissionsState(); dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id)); dumpRuntimePermissionsLPr(pw, prefix + " ", permissionsState - .getRuntimePermissions(user.id)); + .getRuntimePermissionStates(user.id)); } ArraySet<String> cmp = ps.getDisabledComponents(user.id); @@ -4071,7 +4106,8 @@ final class Settings { for (int userId : UserManagerService.getInstance().getUserIds()) { final int[] gids = permissionsState.computeGids(userId); - Set<String> permissions = permissionsState.getRuntimePermissions(userId); + List<PermissionState> permissions = permissionsState + .getRuntimePermissionStates(userId); if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) { pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": "); dumpGidsLPr(pw, prefix + " ", gids); @@ -4120,22 +4156,29 @@ final class Settings { } } - void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, Set<String> permissions) { - if (!permissions.isEmpty()) { + void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, + List<PermissionState> permissionStates) { + if (!permissionStates.isEmpty()) { pw.print(prefix); pw.println("runtime permissions:"); - for (String permission : permissions) { - pw.print(prefix); pw.print(" "); pw.println(permission); + for (PermissionState permissionState : permissionStates) { + pw.print(prefix); pw.print(" "); pw.print(permissionState.getName()); + pw.print(", granted="); pw.print(permissionState.isGranted()); + pw.print(", flags=0x"); pw.println(Integer.toHexString( + permissionState.getFlags())); } } } void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, PermissionsState permissionsState) { - Set<String> permissions = permissionsState.getInstallPermissions(); - if (!permissions.isEmpty()) { + List<PermissionState> permissionStates = permissionsState.getInstallPermissionStates(); + if (!permissionStates.isEmpty()) { pw.print(prefix); pw.println("install permissions:"); - for (String permission : permissions) { - pw.print(prefix); pw.print(" "); pw.println(permission); + for (PermissionState permissionState : permissionStates) { + pw.print(prefix); pw.print(" "); pw.print(permissionState.getName()); + pw.print(", granted="); pw.print(permissionState.isGranted()); + pw.print(", flags=0x"); pw.println(Integer.toHexString( + permissionState.getFlags())); } } } @@ -4207,8 +4250,8 @@ final class Settings { private void writePermissionsSync(int userId) { AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId)); - ArrayMap<String, Set<String>> permissionsForPackage = new ArrayMap<>(); - ArrayMap<String, Set<String>> permissionsForSharedUser = new ArrayMap<>(); + ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>(); + ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>(); synchronized (mLock) { mWriteScheduled.delete(userId); @@ -4219,9 +4262,10 @@ final class Settings { PackageSetting packageSetting = mPackages.valueAt(i); if (packageSetting.sharedUser == null) { PermissionsState permissionsState = packageSetting.getPermissionsState(); - Set<String> permissions = permissionsState.getRuntimePermissions(userId); - if (!permissions.isEmpty()) { - permissionsForPackage.put(packageName, permissions); + List<PermissionState> permissionsStates = permissionsState + .getRuntimePermissionStates(userId); + if (!permissionsStates.isEmpty()) { + permissionsForPackage.put(packageName, permissionsStates); } } } @@ -4231,9 +4275,10 @@ final class Settings { String sharedUserName = mSharedUsers.keyAt(i); SharedUserSetting sharedUser = mSharedUsers.valueAt(i); PermissionsState permissionsState = sharedUser.getPermissionsState(); - Set<String> permissions = permissionsState.getRuntimePermissions(userId); - if (!permissions.isEmpty()) { - permissionsForSharedUser.put(sharedUserName, permissions); + List<PermissionState> permissionsStates = permissionsState + .getRuntimePermissionStates(userId); + if (!permissionsStates.isEmpty()) { + permissionsForSharedUser.put(sharedUserName, permissionsStates); } } } @@ -4252,20 +4297,20 @@ final class Settings { final int packageCount = permissionsForPackage.size(); for (int i = 0; i < packageCount; i++) { String packageName = permissionsForPackage.keyAt(i); - Set<String> permissions = permissionsForPackage.valueAt(i); + List<PermissionState> permissionStates = permissionsForPackage.valueAt(i); serializer.startTag(null, TAG_PACKAGE); serializer.attribute(null, ATTR_NAME, packageName); - writePermissions(serializer, permissions); + writePermissions(serializer, permissionStates); serializer.endTag(null, TAG_PACKAGE); } final int sharedUserCount = permissionsForSharedUser.size(); for (int i = 0; i < sharedUserCount; i++) { String packageName = permissionsForSharedUser.keyAt(i); - Set<String> permissions = permissionsForSharedUser.valueAt(i); + List<PermissionState> permissionStates = permissionsForSharedUser.valueAt(i); serializer.startTag(null, TAG_SHARED_USER); serializer.attribute(null, ATTR_NAME, packageName); - writePermissions(serializer, permissions); + writePermissions(serializer, permissionStates); serializer.endTag(null, TAG_SHARED_USER); } @@ -4290,20 +4335,23 @@ final class Settings { mHandler.removeMessages(userId); for (SettingBase sb : mPackages.values()) { - revokeRuntimePermissions(sb, userId); + revokeRuntimePermissionsAndClearFlags(sb, userId); } for (SettingBase sb : mSharedUsers.values()) { - revokeRuntimePermissions(sb, userId); + revokeRuntimePermissionsAndClearFlags(sb, userId); } } - private void revokeRuntimePermissions(SettingBase sb, int userId) { + private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) { PermissionsState permissionsState = sb.getPermissionsState(); - for (String permission : permissionsState.getRuntimePermissions(userId)) { - BasePermission bp = mPermissions.get(permission); + for (PermissionState permissionState + : permissionsState.getRuntimePermissionStates(userId)) { + BasePermission bp = mPermissions.get(permissionState.getName()); if (bp != null) { permissionsState.revokeRuntimePermission(bp, userId); + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS, 0); } } } @@ -4391,20 +4439,47 @@ final class Settings { continue; } - if (permissionsState.grantRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name); + String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED); + final boolean granted = grantedStr == null + || Boolean.parseBoolean(grantedStr); + + String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS); + final int flags = (flagsStr != null) + ? Integer.parseInt(flagsStr, 16) : 0; + + if (granted) { + if (permissionsState.grantRuntimePermission(bp, userId) == + PermissionsState.PERMISSION_OPERATION_FAILURE) { + Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name); + } else { + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS, flags); + + } + } else { + if (permissionsState.revokeRuntimePermission(bp, userId) == + PermissionsState.PERMISSION_OPERATION_FAILURE) { + Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name); + } else { + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS, flags); + } } + } break; } } } - private void writePermissions(XmlSerializer serializer, Set<String> permissions) - throws IOException { - for (String permission : permissions) { + private void writePermissions(XmlSerializer serializer, + List<PermissionState> permissionStates) throws IOException { + for (PermissionState permissionState : permissionStates) { serializer.startTag(null, TAG_ITEM); - serializer.attribute(null, ATTR_NAME, permission); + serializer.attribute(null, ATTR_NAME,permissionState.getName()); + serializer.attribute(null, ATTR_GRANTED, + String.valueOf(permissionState.isGranted())); + serializer.attribute(null, ATTR_FLAGS, + Integer.toHexString(permissionState.getFlags())); serializer.endTag(null, TAG_ITEM); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index e6f5e3d..e463fad 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -50,6 +50,8 @@ import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.Xml; +import com.google.android.collect.Sets; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsService; import com.android.internal.util.ArrayUtils; @@ -68,11 +70,9 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; +import java.util.Set; import libcore.io.IoUtils; @@ -88,10 +88,6 @@ public class UserManagerService extends IUserManager.Stub { private static final String ATTR_ID = "id"; private static final String ATTR_CREATION_TIME = "created"; private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn"; - private static final String ATTR_SALT = "salt"; - private static final String ATTR_PIN_HASH = "pinHash"; - private static final String ATTR_FAILED_ATTEMPTS = "failedAttempts"; - private static final String ATTR_LAST_RETRY_MS = "lastAttemptMs"; private static final String ATTR_SERIAL_NO = "serialNumber"; private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber"; private static final String ATTR_PARTIAL = "partial"; @@ -129,16 +125,13 @@ public class UserManagerService extends IUserManager.Stub { private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms - // Number of attempts before jumping to the next BACKOFF_TIMES slot - private static final int BACKOFF_INC_INTERVAL = 5; - // Maximum number of managed profiles permitted is 1. This cannot be increased // without first making sure that the rest of the framework is prepared for it. private static final int MAX_MANAGED_PROFILES = 1; - // Amount of time to force the user to wait before entering the PIN again, after failing - // BACKOFF_INC_INTERVAL times. - private static final int[] BACKOFF_TIMES = { 0, 30*1000, 60*1000, 5*60*1000, 30*60*1000 }; + // Set of user restrictions, which can only be enforced by the system + private static final Set<String> SYSTEM_CONTROLLED_RESTRICTIONS = Sets.newArraySet( + UserManager.DISALLOW_RECORD_AUDIO); static final int WRITE_USER_MSG = 1; static final int WRITE_USER_DELAY = 2*1000; // 2 seconds @@ -158,16 +151,6 @@ public class UserManagerService extends IUserManager.Stub { private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>(); private final Bundle mGuestRestrictions = new Bundle(); - class RestrictionsPinState { - long salt; - String pinHash; - int failedAttempts; - long lastAttemptTime; - } - - private final SparseArray<RestrictionsPinState> mRestrictionsPinStates = - new SparseArray<RestrictionsPinState>(); - /** * Set of user IDs being actively removed. Removed IDs linger in this set * for several seconds to work around a VFS caching issue. @@ -258,7 +241,7 @@ public class UserManagerService extends IUserManager.Stub { } } } - userForeground(UserHandle.USER_OWNER); + onUserForeground(UserHandle.USER_OWNER); mAppOpsService = IAppOpsService.Stub.asInterface( ServiceManager.getService(Context.APP_OPS_SERVICE)); for (int i = 0; i < mUserIds.length; ++i) { @@ -524,7 +507,7 @@ public class UserManagerService extends IUserManager.Stub { public boolean hasUserRestriction(String restrictionKey, int userId) { synchronized (mPackagesLock) { Bundle restrictions = mUserRestrictions.get(userId); - return restrictions != null ? restrictions.getBoolean(restrictionKey) : false; + return restrictions != null && restrictions.getBoolean(restrictionKey); } } @@ -539,23 +522,57 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public void setUserRestriction(String key, boolean value, int userId) { + synchronized (mPackagesLock) { + if (!SYSTEM_CONTROLLED_RESTRICTIONS.contains(key)) { + Bundle restrictions = getUserRestrictions(userId); + restrictions.putBoolean(key, value); + setUserRestrictionsInternalLocked(restrictions, userId); + } + } + } + + @Override + public void setSystemControlledUserRestriction(String key, boolean value, int userId) { + checkSystemOrRoot("setSystemControlledUserRestriction"); + synchronized (mPackagesLock) { + Bundle restrictions = getUserRestrictions(userId); + restrictions.putBoolean(key, value); + setUserRestrictionsInternalLocked(restrictions, userId); + } + } + + @Override public void setUserRestrictions(Bundle restrictions, int userId) { checkManageUsersPermission("setUserRestrictions"); if (restrictions == null) return; synchronized (mPackagesLock) { - mUserRestrictions.get(userId).clear(); - mUserRestrictions.get(userId).putAll(restrictions); - long token = Binder.clearCallingIdentity(); - try { - mAppOpsService.setUserRestrictions(mUserRestrictions.get(userId), userId); - } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); - } finally { - Binder.restoreCallingIdentity(token); + final Bundle oldUserRestrictions = mUserRestrictions.get(userId); + // Restore the original state of system controlled restrictions from oldUserRestrictions + for (String key : SYSTEM_CONTROLLED_RESTRICTIONS) { + restrictions.remove(key); + if (oldUserRestrictions.containsKey(key)) { + restrictions.putBoolean(key, oldUserRestrictions.getBoolean(key)); + } } - scheduleWriteUserLocked(mUsers.get(userId)); + setUserRestrictionsInternalLocked(restrictions, userId); + } + } + + private void setUserRestrictionsInternalLocked(Bundle restrictions, int userId) { + final Bundle userRestrictions = mUserRestrictions.get(userId); + userRestrictions.clear(); + userRestrictions.putAll(restrictions); + long token = Binder.clearCallingIdentity(); + try { + mAppOpsService.setUserRestrictions(userRestrictions, userId); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); + } finally { + Binder.restoreCallingIdentity(token); } + scheduleWriteUserLocked(mUsers.get(userId)); } /** @@ -593,6 +610,13 @@ public class UserManagerService extends IUserManager.Stub { } } + private static void checkSystemOrRoot(String message) { + final int uid = Binder.getCallingUid(); + if (uid != Process.SYSTEM_UID && uid != 0) { + throw new SecurityException("Only system may call: " + message); + } + } + private void writeBitmapLocked(UserInfo info, Bitmap bitmap) { try { File dir = new File(mUsersDir, Integer.toString(info.id)); @@ -810,21 +834,6 @@ public class UserManagerService extends IUserManager.Stub { serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime)); serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME, Long.toString(userInfo.lastLoggedInTime)); - RestrictionsPinState pinState = mRestrictionsPinStates.get(userInfo.id); - if (pinState != null) { - if (pinState.salt != 0) { - serializer.attribute(null, ATTR_SALT, Long.toString(pinState.salt)); - } - if (pinState.pinHash != null) { - serializer.attribute(null, ATTR_PIN_HASH, pinState.pinHash); - } - if (pinState.failedAttempts != 0) { - serializer.attribute(null, ATTR_FAILED_ATTEMPTS, - Integer.toString(pinState.failedAttempts)); - serializer.attribute(null, ATTR_LAST_RETRY_MS, - Long.toString(pinState.lastAttemptTime)); - } - } if (userInfo.iconPath != null) { serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath); } @@ -944,11 +953,7 @@ public class UserManagerService extends IUserManager.Stub { String iconPath = null; long creationTime = 0L; long lastLoggedInTime = 0L; - long salt = 0L; - String pinHash = null; - int failedAttempts = 0; int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID; - long lastAttemptTime = 0L; boolean partial = false; boolean guestToRemove = false; Bundle restrictions = new Bundle(); @@ -982,10 +987,6 @@ public class UserManagerService extends IUserManager.Stub { iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH); creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0); lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0); - salt = readLongAttribute(parser, ATTR_SALT, 0L); - pinHash = parser.getAttributeValue(null, ATTR_PIN_HASH); - failedAttempts = readIntAttribute(parser, ATTR_FAILED_ATTEMPTS, 0); - lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L); profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID, UserInfo.NO_PROFILE_GROUP_ID); String valueString = parser.getAttributeValue(null, ATTR_PARTIAL); @@ -1023,17 +1024,6 @@ public class UserManagerService extends IUserManager.Stub { userInfo.guestToRemove = guestToRemove; userInfo.profileGroupId = profileGroupId; mUserRestrictions.append(id, restrictions); - if (salt != 0L) { - RestrictionsPinState pinState = mRestrictionsPinStates.get(id); - if (pinState == null) { - pinState = new RestrictionsPinState(); - mRestrictionsPinStates.put(id, pinState); - } - pinState.salt = salt; - pinState.pinHash = pinHash; - pinState.failedAttempts = failedAttempts; - pinState.lastAttemptTime = lastAttemptTime; - } return userInfo; } catch (IOException ioe) { @@ -1435,8 +1425,6 @@ public class UserManagerService extends IUserManager.Stub { // Remove this user from the list mUsers.remove(userHandle); - - mRestrictionsPinStates.remove(userHandle); // Remove user file AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX)); userFile.delete(); @@ -1508,92 +1496,6 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public boolean setRestrictionsChallenge(String newPin) { - checkManageUsersPermission("Only system can modify the restrictions pin"); - int userId = UserHandle.getCallingUserId(); - synchronized (mPackagesLock) { - RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); - if (pinState == null) { - pinState = new RestrictionsPinState(); - } - if (newPin == null) { - pinState.salt = 0; - pinState.pinHash = null; - } else { - try { - pinState.salt = SecureRandom.getInstance("SHA1PRNG").nextLong(); - } catch (NoSuchAlgorithmException e) { - pinState.salt = (long) (Math.random() * Long.MAX_VALUE); - } - pinState.pinHash = passwordToHash(newPin, pinState.salt); - pinState.failedAttempts = 0; - } - mRestrictionsPinStates.put(userId, pinState); - writeUserLocked(mUsers.get(userId)); - } - return true; - } - - @Override - public int checkRestrictionsChallenge(String pin) { - checkManageUsersPermission("Only system can verify the restrictions pin"); - int userId = UserHandle.getCallingUserId(); - synchronized (mPackagesLock) { - RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); - // If there's no pin set, return error code - if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) { - return UserManager.PIN_VERIFICATION_FAILED_NOT_SET; - } else if (pin == null) { - // If just checking if user can be prompted, return remaining time - int waitTime = getRemainingTimeForPinAttempt(pinState); - Slog.d(LOG_TAG, "Remaining waittime peek=" + waitTime); - return waitTime; - } else { - int waitTime = getRemainingTimeForPinAttempt(pinState); - Slog.d(LOG_TAG, "Remaining waittime=" + waitTime); - if (waitTime > 0) { - return waitTime; - } - if (passwordToHash(pin, pinState.salt).equals(pinState.pinHash)) { - pinState.failedAttempts = 0; - scheduleWriteUserLocked(mUsers.get(userId)); - return UserManager.PIN_VERIFICATION_SUCCESS; - } else { - pinState.failedAttempts++; - pinState.lastAttemptTime = System.currentTimeMillis(); - scheduleWriteUserLocked(mUsers.get(userId)); - return waitTime; - } - } - } - } - - private int getRemainingTimeForPinAttempt(RestrictionsPinState pinState) { - int backoffIndex = Math.min(pinState.failedAttempts / BACKOFF_INC_INTERVAL, - BACKOFF_TIMES.length - 1); - int backoffTime = (pinState.failedAttempts % BACKOFF_INC_INTERVAL) == 0 ? - BACKOFF_TIMES[backoffIndex] : 0; - return (int) Math.max(backoffTime + pinState.lastAttemptTime - System.currentTimeMillis(), - 0); - } - - @Override - public boolean hasRestrictionsChallenge() { - int userId = UserHandle.getCallingUserId(); - synchronized (mPackagesLock) { - return hasRestrictionsPinLocked(userId); - } - } - - private boolean hasRestrictionsPinLocked(int userId) { - RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); - if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) { - return false; - } - return true; - } - - @Override public void removeRestrictions() { checkManageUsersPermission("Only system can remove restrictions"); final int userHandle = UserHandle.getCallingUserId(); @@ -1604,8 +1506,6 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mPackagesLock) { // Remove all user restrictions setUserRestrictions(new Bundle(), userHandle); - // Remove restrictions pin - setRestrictionsChallenge(null); // Remove any app restrictions cleanAppRestrictions(userHandle); } @@ -1637,42 +1537,6 @@ public class UserManagerService extends IUserManager.Stub { } }); } - - /* - * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash. - * Not the most secure, but it is at least a second level of protection. First level is that - * the file is in a location only readable by the system process. - * @param password the password. - * @param salt the randomly generated salt - * @return the hash of the pattern in a String. - */ - private String passwordToHash(String password, long salt) { - if (password == null) { - return null; - } - String algo = null; - String hashed = salt + password; - try { - byte[] saltedPassword = (password + salt).getBytes(); - byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword); - byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword); - hashed = toHex(sha1) + toHex(md5); - } catch (NoSuchAlgorithmException e) { - Log.w(LOG_TAG, "Failed to encode string because of missing algorithm: " + algo); - } - return hashed; - } - - private static String toHex(byte[] ary) { - final String hex = "0123456789ABCDEF"; - String ret = ""; - for (int i = 0; i < ary.length; i++) { - ret += hex.charAt((ary[i] >> 4) & 0xf); - ret += hex.charAt(ary[i] & 0xf); - } - return ret; - } - private int getUidForPackage(String packageName) { long ident = Binder.clearCallingIdentity(); try { @@ -1920,7 +1784,7 @@ public class UserManagerService extends IUserManager.Stub { * Make a note of the last started time of a user and do some cleanup. * @param userId the user that was just foregrounded */ - public void userForeground(int userId) { + public void onUserForeground(int userId) { synchronized (mPackagesLock) { UserInfo user = mUsers.get(userId); long now = System.currentTimeMillis(); @@ -1958,11 +1822,6 @@ public class UserManagerService extends IUserManager.Stub { return RESTRICTIONS_FILE_PREFIX + packageName + XML_SUFFIX; } - private String restrictionsFileNameToPackage(String fileName) { - return fileName.substring(RESTRICTIONS_FILE_PREFIX.length(), - (int) (fileName.length() - XML_SUFFIX.length())); - } - @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index f790f75..74df0a0 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -69,6 +69,7 @@ import android.view.WindowManagerPolicy; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import libcore.util.Objects; @@ -149,6 +150,12 @@ public final class PowerManagerService extends SystemService private static final int POWER_HINT_INTERACTION = 2; private static final int POWER_HINT_LOW_POWER = 5; + // Power features defined in hardware/libhardware/include/hardware/power.h. + private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1; + + // Default setting for double tap to wake. + private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0; + private final Context mContext; private final ServiceThread mHandlerThread; private final PowerManagerHandler mHandler; @@ -338,6 +345,9 @@ public final class PowerManagerService extends SystemService // Otherwise the user won't get much screen on time before dimming occurs. private float mMaximumScreenDimRatioConfig; + // Whether device supports double tap to wake. + private boolean mSupportsDoubleTapWakeConfig; + // The screen off timeout setting value in milliseconds. private int mScreenOffTimeoutSetting; @@ -423,9 +433,15 @@ public final class PowerManagerService extends SystemService // True if we are currently in device idle mode. private boolean mDeviceIdleMode; + // Set of app ids that we will always respect the wake locks for. + int[] mDeviceIdleWhitelist = new int[0]; + // True if theater mode is enabled private boolean mTheaterModeEnabled; + // True if double tap to wake is enabled + private boolean mDoubleTapWakeEnabled; + private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(); @@ -436,6 +452,7 @@ public final class PowerManagerService extends SystemService private static native void nativeSetInteractive(boolean enable); private static native void nativeSetAutoSuspend(boolean enable); private static native void nativeSendPowerHint(int hintId, int data); + private static native void nativeSetFeature(int featureId, int data); public PowerManagerService(Context context) { super(context); @@ -458,6 +475,7 @@ public final class PowerManagerService extends SystemService nativeInit(); nativeSetAutoSuspend(false); nativeSetInteractive(true); + nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0); } } @@ -576,6 +594,9 @@ public final class PowerManagerService extends SystemService resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.THEATER_MODE_ON), false, mSettingsObserver, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.DOUBLE_TAP_TO_WAKE), + false, mSettingsObserver, UserHandle.USER_ALL); // Go. readConfigurationLocked(); updateSettingsLocked(); @@ -621,6 +642,8 @@ public final class PowerManagerService extends SystemService com.android.internal.R.integer.config_maximumScreenDimDuration); mMaximumScreenDimRatioConfig = resources.getFraction( com.android.internal.R.fraction.config_maximumScreenDimRatio, 1, 1); + mSupportsDoubleTapWakeConfig = resources.getBoolean( + com.android.internal.R.bool.config_supportDoubleTapWake); } private void updateSettingsLocked() { @@ -649,6 +672,16 @@ public final class PowerManagerService extends SystemService mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0) == 1; + if (mSupportsDoubleTapWakeConfig) { + boolean doubleTapWakeEnabled = Settings.Secure.getIntForUser(resolver, + Settings.Secure.DOUBLE_TAP_TO_WAKE, DEFAULT_DOUBLE_TAP_TO_WAKE, + UserHandle.USER_CURRENT) != 0; + if (doubleTapWakeEnabled != mDoubleTapWakeEnabled) { + mDoubleTapWakeEnabled = doubleTapWakeEnabled; + nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled ? 1 : 0); + } + } + final int oldScreenBrightnessSetting = mScreenBrightnessSetting; mScreenBrightnessSetting = Settings.System.getIntForUser(resolver, Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessSettingDefault, @@ -758,6 +791,7 @@ public final class PowerManagerService extends SystemService throw new IllegalArgumentException("Wake lock is already dead."); } mWakeLocks.add(wakeLock); + setWakeLockDisabledStateLocked(wakeLock); notifyAcquire = true; } @@ -894,7 +928,7 @@ public final class PowerManagerService extends SystemService } private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) { - if (mSystemReady) { + if (mSystemReady && !wakeLock.mDisabled) { wakeLock.mNotifiedAcquired = true; mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource, @@ -1388,7 +1422,10 @@ public final class PowerManagerService extends SystemService final WakeLock wakeLock = mWakeLocks.get(i); switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { case PowerManager.PARTIAL_WAKE_LOCK: - mWakeLockSummary |= WAKE_LOCK_CPU; + if (!wakeLock.mDisabled) { + // We only respect this if the wake lock is not disabled. + mWakeLockSummary |= WAKE_LOCK_CPU; + } break; case PowerManager.FULL_WAKE_LOCK: mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT; @@ -2248,12 +2285,12 @@ public final class PowerManagerService extends SystemService } } - private void setStayOnSettingInternal(int val) { + void setStayOnSettingInternal(int val) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.STAY_ON_WHILE_PLUGGED_IN, val); } - private void setMaximumScreenOffTimeoutFromDeviceAdminInternal(int timeMs) { + void setMaximumScreenOffTimeoutFromDeviceAdminInternal(int timeMs) { synchronized (mLock) { mMaximumScreenOffTimeoutFromDeviceAdmin = timeMs; mDirty |= DIRTY_SETTINGS; @@ -2261,6 +2298,69 @@ public final class PowerManagerService extends SystemService } } + void setDeviceIdleModeInternal(boolean enabled) { + synchronized (mLock) { + if (mDeviceIdleMode != enabled) { + mDeviceIdleMode = enabled; + updateWakeLockDisabledStatesLocked(); + } + } + } + + void setDeviceIdleWhitelistInternal(int[] appids) { + synchronized (mLock) { + mDeviceIdleWhitelist = appids; + if (mDeviceIdleMode) { + updateWakeLockDisabledStatesLocked(); + } + } + } + + private void updateWakeLockDisabledStatesLocked() { + boolean changed = false; + final int numWakeLocks = mWakeLocks.size(); + for (int i = 0; i < numWakeLocks; i++) { + final WakeLock wakeLock = mWakeLocks.get(i); + if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) + == PowerManager.PARTIAL_WAKE_LOCK) { + if (setWakeLockDisabledStateLocked(wakeLock)) { + changed = true; + if (wakeLock.mDisabled) { + // This wake lock is no longer being respected. + notifyWakeLockReleasedLocked(wakeLock); + } else { + notifyWakeLockAcquiredLocked(wakeLock); + } + } + } + } + if (changed) { + mDirty |= DIRTY_WAKE_LOCKS; + updatePowerStateLocked(); + } + } + + private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) { + if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) + == PowerManager.PARTIAL_WAKE_LOCK) { + boolean disabled = false; + if (mDeviceIdleMode) { + final int appid = UserHandle.getAppId(wakeLock.mOwnerUid); + // 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) { + disabled = true; + } + } + if (wakeLock.mDisabled != disabled) { + wakeLock.mDisabled = disabled; + return true; + } + } + return false; + } + private boolean isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() { return mMaximumScreenOffTimeoutFromDeviceAdmin >= 0 && mMaximumScreenOffTimeoutFromDeviceAdmin < Integer.MAX_VALUE; @@ -2459,6 +2559,8 @@ public final class PowerManagerService extends SystemService pw.println(" mSandmanSummoned=" + mSandmanSummoned); pw.println(" mLowPowerModeEnabled=" + mLowPowerModeEnabled); pw.println(" mBatteryLevelLow=" + mBatteryLevelLow); + pw.println(" mDeviceIdleMode=" + mDeviceIdleMode); + pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist)); pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime)); pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime)); pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime)); @@ -2537,6 +2639,7 @@ public final class PowerManagerService extends SystemService pw.println(" mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum); pw.println(" mScreenBrightnessSettingMaximum=" + mScreenBrightnessSettingMaximum); pw.println(" mScreenBrightnessSettingDefault=" + mScreenBrightnessSettingDefault); + pw.println(" mDoubleTapWakeEnabled=" + mDoubleTapWakeEnabled); final int sleepTimeout = getSleepTimeoutLocked(); final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout); @@ -2671,6 +2774,7 @@ public final class PowerManagerService extends SystemService public final int mOwnerUid; public final int mOwnerPid; public boolean mNotifiedAcquired; + public boolean mDisabled; public WakeLock(IBinder lock, int flags, String tag, String packageName, WorkSource workSource, String historyTag, int ownerUid, int ownerPid) { @@ -2729,7 +2833,7 @@ public final class PowerManagerService extends SystemService @Override public String toString() { return getLockLevelString() - + " '" + mTag + "'" + getLockFlagsString() + + " '" + mTag + "'" + getLockFlagsString() + (mDisabled ? " DISABLED" : "") + " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")"; } @@ -3340,9 +3444,12 @@ public final class PowerManagerService extends SystemService @Override public void setDeviceIdleMode(boolean enabled) { - synchronized (mLock) { - mDeviceIdleMode = enabled; - } + setDeviceIdleModeInternal(enabled); + } + + @Override + public void setDeviceIdleWhitelist(int[] appids) { + setDeviceIdleWhitelistInternal(appids); } } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 56816f9..e649e48 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -1206,7 +1206,7 @@ public final class TvInputManagerService extends SystemService { } @Override - public void requestUnblockContent( + public void unblockContent( IBinder sessionToken, String unblockedRating, int userId) { final int callingUid = Binder.getCallingUid(); final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, @@ -1216,9 +1216,9 @@ public final class TvInputManagerService extends SystemService { synchronized (mLock) { try { getSessionLocked(sessionToken, callingUid, resolvedUserId) - .requestUnblockContent(unblockedRating); + .unblockContent(unblockedRating); } catch (RemoteException | SessionNotFoundException e) { - Slog.e(TAG, "error in requestUnblockContent", e); + Slog.e(TAG, "error in unblockContent", e); } } } finally { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6bf68e8..06d3b22 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -691,6 +691,8 @@ public class WindowManagerService extends IWindowManager.Stub boolean mObscureApplicationContentOnSecondaryDisplays = false; float mPreferredRefreshRate = 0; + + int mPreferredModeId = 0; } final LayoutFields mInnerFields = new LayoutFields(); @@ -9713,6 +9715,10 @@ public class WindowManagerService extends IWindowManager.Stub && w.mAttrs.preferredRefreshRate != 0) { mInnerFields.mPreferredRefreshRate = w.mAttrs.preferredRefreshRate; } + if (mInnerFields.mPreferredModeId == 0 + && w.mAttrs.preferredDisplayModeId != 0) { + mInnerFields.mPreferredModeId = w.mAttrs.preferredDisplayModeId; + } } } } @@ -9846,6 +9852,7 @@ public class WindowManagerService extends IWindowManager.Stub // Reset for each display. mInnerFields.mDisplayHasContent = false; mInnerFields.mPreferredRefreshRate = 0; + mInnerFields.mPreferredModeId = 0; int repeats = 0; do { @@ -10066,6 +10073,7 @@ public class WindowManagerService extends IWindowManager.Stub mDisplayManagerInternal.setDisplayProperties(displayId, mInnerFields.mDisplayHasContent, mInnerFields.mPreferredRefreshRate, + mInnerFields.mPreferredModeId, true /* inTraversal, must call performTraversalInTrans... below */); getDisplayContentLocked(displayId).stopDimmingIfNeeded(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index d6726c1..cdd9503 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1218,6 +1218,10 @@ class WindowStateAnimator { mDtDx = 0; mDsDy = 0; mDtDy = mWin.mGlobalScale; + if (appTransformation == null) { + mHasClipRect = false; + mClipRect.setEmpty(); + } } } @@ -1301,7 +1305,10 @@ class WindowStateAnimator { clipRect.bottom += attrs.surfaceInsets.bottom; // If we have an animated clip rect, intersect it with the clip rect. - if (mHasClipRect) { + // However, the clip rect animation effect should be applied on app windows that inset + // decor only. If applying on non-inset decor one, the top region of this window will + // be clipped on the end of animation, e.g. dialog activities. + if (mHasClipRect && (w.mAttrs.flags & LayoutParams.FLAG_LAYOUT_INSET_DECOR) != 0) { // NOTE: We are adding a temporary workaround due to the status bar // not always reporting the correct system decor rect. In such // cases, we take into account the specified content insets as well. diff --git a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp index 7dbfaf6..39474ec 100644 --- a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp +++ b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp @@ -181,6 +181,21 @@ static jlong nativeGetAuthenticatorId(JNIEnv *, jobject clazz) { return gContext.device->get_authenticator_id(gContext.device); } +static jint nativeSetActiveGroup(JNIEnv *env, jobject clazz, jint gid, jbyteArray path) { + const int pathSize = env->GetArrayLength(path); + jbyte* pathData = env->GetByteArrayElements(path, 0); + if (pathSize >= PATH_MAX) { + ALOGE("Path name is too long\n"); + return -1; + } + char path_name[PATH_MAX] = {0}; + memcpy(path_name, pathData, pathSize); + ALOG(LOG_VERBOSE, LOG_TAG, "nativeSetActiveGroup() path: %s, gid: %d\n", path_name, gid); + int result = gContext.device->set_active_group(gContext.device, gid, path_name); + env->ReleaseByteArrayElements(path, pathData, 0); + return result; +} + static jint nativeOpenHal(JNIEnv* env, jobject clazz) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n"); int err; @@ -242,6 +257,7 @@ static const JNINativeMethod g_methods[] = { { "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate }, { "nativeStopAuthentication", "()I", (void*)nativeStopAuthentication }, { "nativeEnroll", "([BII)I", (void*)nativeEnroll }, + { "nativeSetActiveGroup", "(I[B)I", (void*)nativeSetActiveGroup }, { "nativePreEnroll", "()J", (void*)nativePreEnroll }, { "nativeStopEnrollment", "()I", (void*)nativeStopEnrollment }, { "nativeRemove", "(II)I", (void*)nativeRemove }, diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 6dcdd9d..1662755 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -156,6 +156,14 @@ static void nativeSendPowerHint(JNIEnv *env, jclass clazz, jint hintId, jint dat } } +static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) { + int data_param = data; + + if (gPowerModule && gPowerModule->setFeature) { + gPowerModule->setFeature(gPowerModule, (feature_t)featureId, data_param); + } +} + // ---------------------------------------------------------------------------- static JNINativeMethod gPowerManagerServiceMethods[] = { @@ -172,6 +180,8 @@ static JNINativeMethod gPowerManagerServiceMethods[] = { (void*) nativeSetAutoSuspend }, { "nativeSendPowerHint", "(II)V", (void*) nativeSendPowerHint }, + { "nativeSetFeature", "(II)V", + (void*) nativeSetFeature }, }; #define FIND_CLASS(var, className) \ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java index 28ffc57..88bf54e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java @@ -17,6 +17,7 @@ package com.android.server.devicepolicy; import android.app.AppGlobals; +import android.app.admin.SystemUpdatePolicy; import android.content.ComponentName; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -78,7 +79,7 @@ class DeviceOwner { private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>(); // Local system update policy controllable by device owner. - private PersistableBundle mSystemUpdatePolicy; + private SystemUpdatePolicy mSystemUpdatePolicy; // Private default constructor. private DeviceOwner() { @@ -192,11 +193,11 @@ class DeviceOwner { return mProfileOwners.keySet(); } - PersistableBundle getSystemUpdatePolicy() { + SystemUpdatePolicy getSystemUpdatePolicy() { return mSystemUpdatePolicy; } - void setSystemUpdatePolicy(PersistableBundle systemUpdatePolicy) { + void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) { mSystemUpdatePolicy = systemUpdatePolicy; } @@ -291,7 +292,7 @@ class DeviceOwner { } mProfileOwners.put(userId, profileOwnerInfo); } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) { - mSystemUpdatePolicy = PersistableBundle.restoreFromXml(parser); + mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser); } else { throw new XmlPullParserException( "Unexpected tag in device owner file: " + tag); @@ -361,11 +362,7 @@ class DeviceOwner { // Write system update policy tag if (mSystemUpdatePolicy != null) { out.startTag(null, TAG_SYSTEM_UPDATE_POLICY); - try { - mSystemUpdatePolicy.saveToXml(out); - } catch (XmlPullParserException e) { - Slog.e(TAG, "Failed to save system update policy", e); - } + mSystemUpdatePolicy.saveToXml(out); out.endTag(null, TAG_SYSTEM_UPDATE_POLICY); } out.endDocument(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6f01ca0..ba5d666 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -39,6 +39,7 @@ import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.IDevicePolicyManager; +import android.app.admin.SystemUpdatePolicy; import android.app.backup.IBackupManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -2897,7 +2898,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean callerIsDeviceOwnerAdmin = isCallerDeviceOwnerOrInitializer(callingUid); boolean doNotAskCredentialsOnBoot = - (flags & DevicePolicyManager.DO_NOT_ASK_CREDENTIALS_ON_BOOT) != 0; + (flags & DevicePolicyManager.RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT) != 0; if (callerIsDeviceOwnerAdmin && doNotAskCredentialsOnBoot) { setDoNotAskCredentialsOnBoot(); } @@ -6238,7 +6239,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setSystemUpdatePolicy(ComponentName who, PersistableBundle policy) { + public void setSystemUpdatePolicy(ComponentName who, SystemUpdatePolicy policy) { + if (policy != null && !policy.isValid()) { + throw new IllegalArgumentException("Invalid system update policy."); + } synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); if (policy == null) { @@ -6254,9 +6258,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public PersistableBundle getSystemUpdatePolicy() { + public SystemUpdatePolicy getSystemUpdatePolicy() { synchronized (this) { - return mDeviceOwner.getSystemUpdatePolicy(); + SystemUpdatePolicy policy = mDeviceOwner.getSystemUpdatePolicy(); + if (policy != null && !policy.isValid()) { + Slog.w(LOG_TAG, "Stored system update policy is invalid, return null instead."); + return null; + } + return policy; } } @@ -6344,10 +6353,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long ident = Binder.clearCallingIdentity(); try { + PackageManager packageManager = mContext.getPackageManager(); if (granted) { - mContext.getPackageManager().grantPermission(packageName, permission, user); + packageManager.grantRuntimePermission(packageName, permission, user); + packageManager.updatePermissionFlags(permission, packageName, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, user); } else { - mContext.getPackageManager().revokePermission(packageName, permission, user); + packageManager.revokeRuntimePermission(packageName, + permission, user); + packageManager.updatePermissionFlags(permission, packageName, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, user); } return true; } catch (SecurityException se) { diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index 869d6e1..d6ff475 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -48,6 +48,7 @@ class IntervalStats { usageStats.mPackageName = getCachedStringRef(packageName); usageStats.mBeginTimeStamp = beginTime; usageStats.mEndTimeStamp = endTime; + usageStats.mBeginIdleTime = endTime; packageStats.put(usageStats.mPackageName, usageStats); } return usageStats; @@ -119,6 +120,17 @@ class IntervalStats { endTime = timeStamp; } + /** + * Updates the last active time for the package. The timestamp uses a timebase that + * tracks the device usage time. + * @param packageName + * @param timeStamp + */ + void updateBeginIdleTime(String packageName, long timeStamp) { + UsageStats usageStats = getOrCreateUsageStats(packageName); + usageStats.mBeginIdleTime = timeStamp; + } + void updateConfigurationStats(Configuration config, long timeStamp) { if (activeConfiguration != null) { ConfigurationStats activeStats = configurations.get(activeConfiguration); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 117cbe4..197daed 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -40,31 +40,39 @@ import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.database.ContentObserver; +import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.BatteryManager; import android.os.Binder; import android.os.Environment; import android.os.Handler; +import android.os.IDeviceIdleController; import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.ArraySet; +import android.util.AtomicFile; import android.util.Slog; import android.util.SparseArray; +import android.view.Display; -import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.SystemConfig; +import com.android.server.DeviceIdleController; import com.android.server.SystemService; +import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -76,6 +84,7 @@ import java.util.List; */ public class UsageStatsService extends SystemService implements UserUsageStatsService.StatsUpdatedListener { + static final String TAG = "UsageStatsService"; static final boolean DEBUG = false; @@ -91,7 +100,7 @@ public class UsageStatsService extends SystemService implements static final int MSG_FLUSH_TO_DISK = 1; static final int MSG_REMOVE_USER = 2; static final int MSG_INFORM_LISTENERS = 3; - static final int MSG_RESET_LAST_TIMESTAMP = 4; + static final int MSG_FORCE_IDLE_STATE = 4; static final int MSG_CHECK_IDLE_STATES = 5; private final Object mLock = new Object(); @@ -99,16 +108,20 @@ public class UsageStatsService extends SystemService implements AppOpsManager mAppOps; UserManager mUserManager; AppWidgetManager mAppWidgetManager; + IDeviceIdleController mDeviceIdleController; + private DisplayManager mDisplayManager; private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>(); private File mUsageStatsDir; long mRealTimeSnapshot; long mSystemTimeSnapshot; boolean mAppIdleParoled; + private boolean mScreenOn; long mAppIdleDurationMillis; - long mCheckIdleIntervalMillis = DEFAULT_CHECK_IDLE_INTERVAL; + long mScreenOnTime; + long mScreenOnSystemTimeSnapshot; private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>(); @@ -162,6 +175,18 @@ public class UsageStatsService extends SystemService implements // Observe changes to the threshold new SettingsObserver(mHandler).registerObserver(); mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class); + mDeviceIdleController = IDeviceIdleController.Stub.asInterface( + ServiceManager.getService(DeviceIdleController.SERVICE_NAME)); + mDisplayManager = (DisplayManager) getContext().getSystemService( + Context.DISPLAY_SERVICE); + mScreenOnSystemTimeSnapshot = System.currentTimeMillis(); + synchronized (this) { + mScreenOnTime = readScreenOnTimeLocked(); + } + mDisplayManager.registerDisplayListener(mDisplayListener, null); + synchronized (this) { + updateDisplayLocked(); + } } else if (phase == PHASE_BOOT_COMPLETED) { setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging()); } @@ -195,6 +220,24 @@ public class UsageStatsService extends SystemService implements } } + private final DisplayManager.DisplayListener mDisplayListener + = new DisplayManager.DisplayListener() { + + @Override public void onDisplayAdded(int displayId) { + } + + @Override public void onDisplayRemoved(int displayId) { + } + + @Override public void onDisplayChanged(int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + synchronized (UsageStatsService.this.mLock) { + updateDisplayLocked(); + } + } + } + }; + @Override public void onStatsUpdated() { mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL); @@ -261,7 +304,7 @@ public class UsageStatsService extends SystemService implements final int packageCount = packages.size(); for (int p = 0; p < packageCount; p++) { final String packageName = packages.get(p).packageName; - final boolean isIdle = isAppIdle(packageName, userId); + final boolean isIdle = isAppIdleFiltered(packageName, userId); mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, isIdle ? 1 : 0, packageName)); } @@ -270,6 +313,61 @@ public class UsageStatsService extends SystemService implements mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis); } + void updateDisplayLocked() { + boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState() + != Display.STATE_OFF; + if (screenOn == mScreenOn) return; + + mScreenOn = screenOn; + long now = System.currentTimeMillis(); + if (mScreenOn) { + mScreenOnSystemTimeSnapshot = now; + } else { + mScreenOnTime += now - mScreenOnSystemTimeSnapshot; + writeScreenOnTimeLocked(mScreenOnTime); + } + } + + private long getScreenOnTimeLocked(long now) { + if (mScreenOn) { + return now - mScreenOnSystemTimeSnapshot + mScreenOnTime; + } else { + return mScreenOnTime; + } + } + + private File getScreenOnTimeFile() { + return new File(mUsageStatsDir, UserHandle.USER_OWNER + "/screen_on_time"); + } + + private long readScreenOnTimeLocked() { + long screenOnTime = 0; + File screenOnTimeFile = getScreenOnTimeFile(); + if (screenOnTimeFile.exists()) { + try { + BufferedReader reader = new BufferedReader(new FileReader(screenOnTimeFile)); + screenOnTime = Long.parseLong(reader.readLine()); + reader.close(); + } catch (IOException | NumberFormatException e) { + } + } else { + writeScreenOnTimeLocked(screenOnTime); + } + return screenOnTime; + } + + private void writeScreenOnTimeLocked(long screenOnTime) { + AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile()); + FileOutputStream fos = null; + try { + fos = screenOnTimeFile.startWrite(); + fos.write(Long.toString(screenOnTime).getBytes()); + screenOnTimeFile.finishWrite(fos); + } catch (IOException ioe) { + screenOnTimeFile.failWrite(fos); + } + } + private static void deleteRecursively(File f) { File[] files = f.listFiles(); if (files != null) { @@ -289,7 +387,7 @@ public class UsageStatsService extends SystemService implements if (service == null) { service = new UserUsageStatsService(getContext(), userId, new File(mUsageStatsDir, Integer.toString(userId)), this); - service.init(currentTimeMillis); + service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis)); mUserState.put(userId, service); } return service; @@ -343,9 +441,10 @@ public class UsageStatsService extends SystemService implements final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow); - final long lastUsed = service.getLastPackageAccessTime(event.mPackage); - final boolean previouslyIdle = hasPassedIdleDuration(lastUsed); - service.reportEvent(event); + final long lastUsed = service.getBeginIdleTime(event.mPackage); + final long screenOnTime = getScreenOnTimeLocked(timeNow); + final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, screenOnTime); + service.reportEvent(event, screenOnTime); // Inform listeners if necessary if ((event.mEventType == Event.MOVE_TO_FOREGROUND || event.mEventType == Event.MOVE_TO_BACKGROUND @@ -360,19 +459,21 @@ public class UsageStatsService extends SystemService implements } /** - * Forces the app's timestamp to reflect idle or active. If idle, then it rolls back the - * last used timestamp to a point in time thats behind the threshold for idle. + * Forces the app's beginIdleTime to reflect idle or active. If idle, then it rolls back the + * beginIdleTime to a point in time thats behind the threshold for idle. */ - void resetLastTimestamp(String packageName, int userId, boolean idle) { + void forceIdleState(String packageName, int userId, boolean idle) { synchronized (mLock) { final long timeNow = checkAndGetTimeLocked(); - final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0) - 5000; + final long screenOnTime = getScreenOnTimeLocked(timeNow); + final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000; final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow); - final long lastUsed = service.getLastPackageAccessTime(packageName); - final boolean previouslyIdle = hasPassedIdleDuration(lastUsed); - service.setLastTimestamp(packageName, lastTimestamp); + final long lastUsed = service.getBeginIdleTime(packageName); + final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, + getScreenOnTimeLocked(timeNow)); + service.setBeginIdleTime(packageName, deviceUsageTime); // Inform listeners if necessary if (previouslyIdle != idle) { // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage); @@ -451,23 +552,25 @@ public class UsageStatsService extends SystemService implements } } - /** - * Called by LocalService stub. - */ - long getLastPackageAccessTime(String packageName, int userId) { + private boolean isAppIdleUnfiltered(String packageName, int userId) { synchronized (mLock) { final long timeNow = checkAndGetTimeLocked(); - // android package is always considered non-idle. - // TODO: Add a generic whitelisting mechanism - if (packageName.equals("android")) { - return timeNow; - } final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow); - return service.getLastPackageAccessTime(packageName); + long beginIdleTime = service.getBeginIdleTime(packageName); + return hasPassedIdleTimeout(beginIdleTime, getScreenOnTimeLocked(timeNow)); } } + /** + * @param timestamp when the app was last used in device usage timebase + * @param currentTime current time in device usage timebase + * @return whether it's been used far enough in the past to be considered inactive + */ + boolean hasPassedIdleTimeout(long timestamp, long currentTime) { + return timestamp <= currentTime - mAppIdleDurationMillis; + } + void addListener(AppIdleStateChangeListener listener) { synchronized (mLock) { if (!mPackageAccessListeners.contains(listener)) { @@ -482,12 +585,13 @@ public class UsageStatsService extends SystemService implements } } - private boolean hasPassedIdleDuration(long lastUsed) { - final long now = System.currentTimeMillis(); - return lastUsed <= now - mAppIdleDurationMillis; - } - - boolean isAppIdle(String packageName, int userId) { + /** + * Checks if an app has been idle for a while and filters out apps that are excluded. + * It returns false if the current system state allows all apps to be considered active. + * This happens if the device is plugged in or temporarily allowed to make exceptions. + * Called by interface impls. + */ + boolean isAppIdleFiltered(String packageName, int userId) { if (packageName == null) return false; synchronized (mLock) { // Temporary exemption, probably due to device charging or occasional allowance to @@ -496,8 +600,12 @@ public class UsageStatsService extends SystemService implements return false; } } - if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) { - return false; + if (packageName.equals("android")) return false; + try { + if (mDeviceIdleController.isPowerSaveWhitelistApp(packageName)) { + return false; + } + } catch (RemoteException re) { } // TODO: Optimize this check if (isActiveDeviceAdmin(packageName, userId)) { @@ -509,14 +617,13 @@ public class UsageStatsService extends SystemService implements return false; } - final long lastUsed = getLastPackageAccessTime(packageName, userId); - return hasPassedIdleDuration(lastUsed); + return isAppIdleUnfiltered(packageName, userId); } void setAppIdle(String packageName, boolean idle, int userId) { if (packageName == null) return; - mHandler.obtainMessage(MSG_RESET_LAST_TIMESTAMP, userId, idle ? 1 : 0, packageName) + mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName) .sendToTarget(); } @@ -559,6 +666,7 @@ public class UsageStatsService extends SystemService implements */ void dump(String[] args, PrintWriter pw) { synchronized (mLock) { + final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked()); IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " "); ArraySet<String> argSet = new ArraySet<>(); argSet.addAll(Arrays.asList(args)); @@ -569,12 +677,13 @@ public class UsageStatsService extends SystemService implements idpw.println(); idpw.increaseIndent(); if (argSet.contains("--checkin")) { - mUserState.valueAt(i).checkin(idpw); + mUserState.valueAt(i).checkin(idpw, screenOnTime); } else { - mUserState.valueAt(i).dump(idpw); + mUserState.valueAt(i).dump(idpw, screenOnTime); } idpw.decreaseIndent(); } + pw.write("Screen On Timestamp:" + mScreenOnTime + "\n"); } } @@ -602,8 +711,8 @@ public class UsageStatsService extends SystemService implements informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1); break; - case MSG_RESET_LAST_TIMESTAMP: - resetLastTimestamp((String) msg.obj, msg.arg1, msg.arg2 == 1); + case MSG_FORCE_IDLE_STATE: + forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1); break; case MSG_CHECK_IDLE_STATES: @@ -718,23 +827,23 @@ public class UsageStatsService extends SystemService implements } @Override - public boolean isAppIdle(String packageName, int userId) { + public boolean isAppInactive(String packageName, int userId) { try { userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, false, true, "isAppIdle", null); + Binder.getCallingUid(), userId, false, true, "isAppInactive", null); } catch (RemoteException re) { return false; } final long token = Binder.clearCallingIdentity(); try { - return UsageStatsService.this.isAppIdle(packageName, userId); + return UsageStatsService.this.isAppIdleFiltered(packageName, userId); } finally { Binder.restoreCallingIdentity(token); } } @Override - public void setAppIdle(String packageName, boolean idle, int userId) { + public void setAppInactive(String packageName, boolean idle, int userId) { final int callingUid = Binder.getCallingUid(); try { userId = ActivityManagerNative.getDefault().handleIncomingUser( @@ -832,12 +941,7 @@ public class UsageStatsService extends SystemService implements @Override public boolean isAppIdle(String packageName, int userId) { - return UsageStatsService.this.isAppIdle(packageName, userId); - } - - @Override - public long getLastPackageAccessTime(String packageName, int userId) { - return UsageStatsService.this.getLastPackageAccessTime(packageName, userId); + return UsageStatsService.this.isAppIdleFiltered(packageName, userId); } @Override diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java index bfb71c5..0111201 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java +++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java @@ -26,6 +26,7 @@ import android.app.usage.TimeSparseArray; import android.app.usage.UsageEvents; import android.app.usage.UsageStats; import android.content.res.Configuration; +import android.text.TextUtils; import java.io.IOException; import java.net.ProtocolException; @@ -54,6 +55,7 @@ final class UsageStatsXmlV1 { // Time attributes stored as an offset of the beginTime. private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive"; + private static final String BEGIN_IDLE_TIME_ATTR = "beginIdleTime"; private static final String END_TIME_ATTR = "endTime"; private static final String TIME_ATTR = "time"; @@ -69,7 +71,10 @@ final class UsageStatsXmlV1 { // Apply the offset to the beginTime to find the absolute time. stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute( parser, LAST_TIME_ACTIVE_ATTR); - + final String beginIdleTime = parser.getAttributeValue(null, BEGIN_IDLE_TIME_ATTR); + if (!TextUtils.isEmpty(beginIdleTime)) { + stats.mBeginIdleTime = Long.parseLong(beginIdleTime); + } stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR); stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR); } @@ -129,6 +134,7 @@ final class UsageStatsXmlV1 { XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName); XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground); XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent); + XmlUtils.writeLongAttribute(xml, BEGIN_IDLE_TIME_ATTR, usageStats.mBeginIdleTime); xml.endTag(null, PACKAGE_TAG); } diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index d94759d..b638c8e 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -80,7 +80,7 @@ class UserUsageStatsService { mUserId = userId; } - void init(final long currentTimeMillis) { + void init(final long currentTimeMillis, final long deviceUsageTime) { mDatabase.init(currentTimeMillis); int nullCount = 0; @@ -135,7 +135,8 @@ class UserUsageStatsService { } if (mDatabase.isNewUpdate()) { - initializeDefaultsForApps(currentTimeMillis, mDatabase.isFirstUpdate()); + initializeDefaultsForApps(currentTimeMillis, deviceUsageTime, + mDatabase.isFirstUpdate()); } } @@ -145,7 +146,8 @@ class UserUsageStatsService { * @param firstUpdate if it is the first update, touch all installed apps, otherwise only * touch the system apps */ - private void initializeDefaultsForApps(long currentTimeMillis, boolean firstUpdate) { + private void initializeDefaultsForApps(long currentTimeMillis, long deviceUsageTime, + boolean firstUpdate) { PackageManager pm = mContext.getPackageManager(); List<PackageInfo> packages = pm.getInstalledPackages(0, mUserId); final int packageCount = packages.size(); @@ -153,9 +155,10 @@ class UserUsageStatsService { final PackageInfo pi = packages.get(i); String packageName = pi.packageName; if (pi.applicationInfo != null && (firstUpdate || pi.applicationInfo.isSystemApp()) - && getLastPackageAccessTime(packageName) == -1) { + && getBeginIdleTime(packageName) == -1) { for (IntervalStats stats : mCurrentStats) { stats.update(packageName, currentTimeMillis, Event.INTERACTION); + stats.updateBeginIdleTime(packageName, deviceUsageTime); mStatsChanged = true; } } @@ -170,7 +173,7 @@ class UserUsageStatsService { loadActiveStats(newTime, true); } - void reportEvent(UsageEvents.Event event) { + void reportEvent(UsageEvents.Event event, long deviceUsageTime) { if (DEBUG) { Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage + "[" + event.mTimeStamp + "]: " @@ -205,6 +208,7 @@ class UserUsageStatsService { stats.updateConfigurationStats(newFullConfig, event.mTimeStamp); } else { stats.update(event.mPackage, event.mTimeStamp, event.mEventType); + stats.updateBeginIdleTime(event.mPackage, deviceUsageTime); } } @@ -215,9 +219,9 @@ class UserUsageStatsService { * Sets the last timestamp for each of the intervals. * @param lastTimestamp */ - void setLastTimestamp(String packageName, long lastTimestamp) { + void setBeginIdleTime(String packageName, long deviceUsageTime) { for (IntervalStats stats : mCurrentStats) { - stats.update(packageName, lastTimestamp, UsageEvents.Event.NONE); + stats.updateBeginIdleTime(packageName, deviceUsageTime); } notifyStatsChanged(); } @@ -376,13 +380,13 @@ class UserUsageStatsService { return new UsageEvents(results, table); } - long getLastPackageAccessTime(String packageName) { + long getBeginIdleTime(String packageName) { final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]; UsageStats packageUsage; if ((packageUsage = yearly.packageStats.get(packageName)) == null) { return -1; } else { - return packageUsage.getLastTimeUsed(); + return packageUsage.getBeginIdleTime(); } } @@ -506,23 +510,23 @@ class UserUsageStatsService { // -- DUMP related methods -- // - void checkin(final IndentingPrintWriter pw) { + void checkin(final IndentingPrintWriter pw, final long screenOnTime) { mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() { @Override public boolean checkin(IntervalStats stats) { - printIntervalStats(pw, stats, false); + printIntervalStats(pw, stats, screenOnTime, false); return true; } }); } - void dump(IndentingPrintWriter pw) { + void dump(IndentingPrintWriter pw, final long screenOnTime) { // This is not a check-in, only dump in-memory stats. for (int interval = 0; interval < mCurrentStats.length; interval++) { pw.print("In-memory "); pw.print(intervalToString(interval)); pw.println(" stats"); - printIntervalStats(pw, mCurrentStats[interval], true); + printIntervalStats(pw, mCurrentStats[interval], screenOnTime, true); } } @@ -540,7 +544,8 @@ class UserUsageStatsService { return Long.toString(elapsedTime); } - void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, boolean prettyDates) { + void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, long screenOnTime, + boolean prettyDates) { if (prettyDates) { pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext, stats.beginTime, stats.endTime, sDateFormatFlags) + "\""); @@ -559,6 +564,8 @@ class UserUsageStatsService { pw.printPair("package", usageStats.mPackageName); pw.printPair("totalTime", formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates)); pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates)); + pw.printPair("inactiveTime", + formatElapsedTime(screenOnTime - usageStats.mBeginIdleTime, prettyDates)); pw.println(); } pw.decreaseIndent(); diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 6adb8be..f84beb6 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -78,8 +78,6 @@ public class UsbDeviceManager { "/sys/class/android_usb/android0/functions"; private static final String STATE_PATH = "/sys/class/android_usb/android0/state"; - private static final String MASS_STORAGE_FILE_PATH = - "/sys/class/android_usb/android0/f_mass_storage/lun/file"; private static final String RNDIS_ETH_ADDR_PATH = "/sys/class/android_usb/android0/f_rndis/ethaddr"; private static final String AUDIO_SOURCE_PCM_PATH = @@ -832,8 +830,6 @@ public class UsbDeviceManager { + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); pw.println(" Kernel function list: " + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); - pw.println(" Mass storage backing file: " - + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim()); } catch (IOException e) { pw.println("IOException: " + e); } @@ -866,15 +862,6 @@ public class UsbDeviceManager { mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault); } - public void setMassStorageBackingFile(String path) { - if (path == null) path = ""; - try { - FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path); - } catch (IOException e) { - Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH); - } - } - private void readOemUsbOverrideConfig() { String[] configList = mContext.getResources().getStringArray( com.android.internal.R.array.config_oemUsbModeOverride); diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index fda8076..e03884f 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -271,16 +271,6 @@ public class UsbService extends IUsbManager.Stub { } @Override - public void setMassStorageBackingFile(String path) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - if (mDeviceManager != null) { - mDeviceManager.setMassStorageBackingFile(path); - } else { - throw new IllegalStateException("USB device mode not supported"); - } - } - - @Override public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey); |