summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java27
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java65
-rw-r--r--services/core/java/com/android/server/GraphicsStatsService.java6
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java1
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java39
-rw-r--r--services/core/java/com/android/server/MountService.java68
-rwxr-xr-xservices/core/java/com/android/server/am/ActiveServices.java74
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java206
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java14
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java14
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java4
-rw-r--r--services/core/java/com/android/server/am/ProviderMap.java27
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java66
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java25
-rw-r--r--services/core/java/com/android/server/display/DisplayAdapter.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java5
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java29
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java186
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java42
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java7
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayWindow.java5
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java12
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java7
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java9
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java12
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java5
-rw-r--r--services/core/java/com/android/server/notification/CalendarTracker.java4
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java4
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java133
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java55
-rw-r--r--services/core/java/com/android/server/pm/BasePermission.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java94
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java174
-rw-r--r--services/core/java/com/android/server/pm/PermissionsState.java415
-rw-r--r--services/core/java/com/android/server/pm/SettingBase.java6
-rw-r--r--services/core/java/com/android/server/pm/Settings.java173
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java261
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java123
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java9
-rw-r--r--services/core/jni/com_android_server_fingerprint_FingerprintService.cpp16
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java15
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java29
-rw-r--r--services/usage/java/com/android/server/usage/IntervalStats.java12
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java206
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsXmlV1.java8
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java35
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java13
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java10
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);