diff options
14 files changed, 327 insertions, 150 deletions
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java index 8e9791f8b731..02a92b9c19ff 100644 --- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java +++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java @@ -58,7 +58,8 @@ public class NfcCommand extends Svc.Command { IPackageManager pm = IPackageManager.Stub.asInterface( ServiceManager.getService("package")); try { - if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0)) { + if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0) || + pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) { INfcAdapter nfc = INfcAdapter.Stub .asInterface(ServiceManager.getService(Context.NFC_SERVICE)); try { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 1e4ffbeca33d..440ddd63147f 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -403,8 +403,8 @@ public class AppOpsManager { OP_WRITE_SMS, OP_RECEIVE_SMS, OP_RECEIVE_SMS, - OP_RECEIVE_SMS, - OP_RECEIVE_SMS, + OP_RECEIVE_MMS, + OP_RECEIVE_WAP_PUSH, OP_SEND_SMS, OP_READ_SMS, OP_WRITE_SMS, diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index c1180e25a0d3..f273cd8670f0 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -26,6 +26,8 @@ import android.system.StructStat; import android.util.Log; import com.google.android.collect.Maps; + +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.XmlUtils; import dalvik.system.BlockGuard; @@ -72,6 +74,14 @@ final class SharedPreferencesImpl implements SharedPreferences { private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>(); + /** Current memory state (always increasing) */ + @GuardedBy("this") + private long mCurrentMemoryStateGeneration; + + /** Latest memory state that was committed to disk */ + @GuardedBy("mWritingToDiskLock") + private long mDiskStateGeneration; + SharedPreferencesImpl(File file, int mode) { mFile = file; mBackupFile = makeBackupFile(file); @@ -289,7 +299,7 @@ final class SharedPreferencesImpl implements SharedPreferences { // Return value from EditorImpl#commitToMemory() private static class MemoryCommitResult { - public boolean changesMade; // any keys different? + public long memoryStateGeneration; public List<String> keysModified; // may be null public Set<OnSharedPreferenceChangeListener> listeners; // may be null public Map<?, ?> mapToWriteToDisk; @@ -412,9 +422,11 @@ final class SharedPreferencesImpl implements SharedPreferences { } synchronized (this) { + boolean changesMade = false; + if (mClear) { if (!mMap.isEmpty()) { - mcr.changesMade = true; + changesMade = true; mMap.clear(); } mClear = false; @@ -441,13 +453,19 @@ final class SharedPreferencesImpl implements SharedPreferences { mMap.put(k, v); } - mcr.changesMade = true; + changesMade = true; if (hasListeners) { mcr.keysModified.add(k); } } mModified.clear(); + + if (changesMade) { + mCurrentMemoryStateGeneration++; + } + + mcr.memoryStateGeneration = mCurrentMemoryStateGeneration; } } return mcr; @@ -509,10 +527,12 @@ final class SharedPreferencesImpl implements SharedPreferences { */ private void enqueueDiskWrite(final MemoryCommitResult mcr, final Runnable postWriteRunnable) { + final boolean isFromSyncCommit = (postWriteRunnable == null); + final Runnable writeToDiskRunnable = new Runnable() { public void run() { synchronized (mWritingToDiskLock) { - writeToFile(mcr); + writeToFile(mcr, isFromSyncCommit); } synchronized (SharedPreferencesImpl.this) { mDiskWritesInFlight--; @@ -523,8 +543,6 @@ final class SharedPreferencesImpl implements SharedPreferences { } }; - final boolean isFromSyncCommit = (postWriteRunnable == null); - // Typical #commit() path with fewer allocations, doing a write on // the current thread. if (isFromSyncCommit) { @@ -538,6 +556,10 @@ final class SharedPreferencesImpl implements SharedPreferences { } } + if (DEBUG) { + Log.d(TAG, "added " + mcr.memoryStateGeneration + " -> " + mFile.getName()); + } + QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable); } @@ -565,17 +587,34 @@ final class SharedPreferencesImpl implements SharedPreferences { } // Note: must hold mWritingToDiskLock - private void writeToFile(MemoryCommitResult mcr) { + private void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) { // Rename the current file so it may be used as a backup during the next read if (mFile.exists()) { - if (!mcr.changesMade) { - // If the file already exists, but no changes were - // made to the underlying map, it's wasteful to - // re-write the file. Return as if we wrote it - // out. + boolean needsWrite = false; + + // Only need to write if the disk state is older than this commit + if (mDiskStateGeneration < mcr.memoryStateGeneration) { + if (isFromSyncCommit) { + needsWrite = true; + } else { + synchronized (this) { + // No need to persist intermediate states. Just wait for the latest state to + // be persisted. + if (mCurrentMemoryStateGeneration == mcr.memoryStateGeneration) { + needsWrite = true; + } + } + } + } + + if (!needsWrite) { + if (DEBUG) { + Log.d(TAG, "skipped " + mcr.memoryStateGeneration + " -> " + mFile.getName()); + } mcr.setDiskWriteResult(true); return; } + if (!mBackupFile.exists()) { if (!mFile.renameTo(mBackupFile)) { Log.e(TAG, "Couldn't rename file " + mFile @@ -599,6 +638,11 @@ final class SharedPreferencesImpl implements SharedPreferences { } XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str); FileUtils.sync(str); + + if (DEBUG) { + Log.d(TAG, "wrote " + mcr.memoryStateGeneration + " -> " + mFile.getName()); + } + str.close(); ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0); try { @@ -612,7 +656,11 @@ final class SharedPreferencesImpl implements SharedPreferences { } // Writing was successful, delete the backup file if there is one. mBackupFile.delete(); + + mDiskStateGeneration = mcr.memoryStateGeneration; + mcr.setDiskWriteResult(true); + return; } catch (XmlPullParserException e) { Log.w(TAG, "writeToFile: Got exception:", e); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a2f9bdd2370d..e23f142317ac 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2016,7 +2016,8 @@ public class DevicePolicyManager { * Determine whether the current password the user has set is sufficient to meet the policy * requirements (e.g. quality, minimum length) that have been requested by the admins of this * user and its participating profiles. Restrictions on profiles that have a separate challenge - * are not taken into account. + * are not taken into account. If the user has a password, it must have been entered in order to + * perform this check. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has @@ -2029,6 +2030,7 @@ public class DevicePolicyManager { * @return Returns true if the password meets the current requirements, else false. * @throws SecurityException if the calling application does not own an active administrator * that uses {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} + * @throws IllegalStateException if the user has a password but has not entered it yet. */ public boolean isActivePasswordSufficient() { if (mService != null) { @@ -3541,6 +3543,19 @@ public class DevicePolicyManager { /** * @hide */ + public void reportPasswordChanged(int userId) { + if (mService != null) { + try { + mService.reportPasswordChanged(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * @hide + */ public void reportFailedPasswordAttempt(int userHandle) { if (mService != null) { try { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index f39cb5ae9fbd..90632a19a09b 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -119,6 +119,7 @@ interface IDevicePolicyManager { void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase, int numbers, int symbols, int nonletter, int userHandle); + void reportPasswordChanged(int userId); void reportFailedPasswordAttempt(int userHandle); void reportSuccessfulPasswordAttempt(int userHandle); void reportFailedFingerprintAttempt(int userHandle); diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index a400d90c64c5..4d9192ba8d24 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -100,13 +100,13 @@ public class Toast { */ public Toast(Context context) { mContext = context; - mTN = new TN(); + mTN = new TN(context.getPackageName()); mTN.mY = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.toast_y_offset); mTN.mGravity = context.getResources().getInteger( com.android.internal.R.integer.config_toastDefaultGravity); } - + /** * Show the view for the specified duration. */ @@ -133,15 +133,9 @@ public class Toast { * after the appropriate duration. */ public void cancel() { - mTN.hide(); - - try { - getService().cancelToast(mContext.getPackageName(), mTN); - } catch (RemoteException e) { - // Empty - } + mTN.cancel(); } - + /** * Set the view to show. * @see #getView @@ -331,18 +325,40 @@ public class Toast { final Runnable mHide = new Runnable() { @Override public void run() { - handleHide(); - // Don't do this in handleHide() because it is also invoked by handleShow() - mNextView = null; } }; private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); + + private static final int SHOW = 0; + private static final int HIDE = 1; + private static final int CANCEL = 2; final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { - IBinder token = (IBinder) msg.obj; - handleShow(token); + switch (msg.what) { + case SHOW: { + IBinder token = (IBinder) msg.obj; + handleShow(token); + break; + } + case HIDE: { + handleHide(); + // Don't do this in handleHide() because it is also invoked by handleShow() + mNextView = null; + break; + } + case CANCEL: { + handleHide(); + // Don't do this in handleHide() because it is also invoked by handleShow() + mNextView = null; + try { + getService().cancelToast(mPackageName, TN.this); + } catch (RemoteException e) { + } + break; + } + } } }; @@ -358,10 +374,12 @@ public class Toast { WindowManager mWM; + String mPackageName; + static final long SHORT_DURATION_TIMEOUT = 5000; static final long LONG_DURATION_TIMEOUT = 1000; - TN() { + TN(String packageName) { // XXX This should be changed to use a Dialog, with a Theme.Toast // defined that sets up the layout params appropriately. final WindowManager.LayoutParams params = mParams; @@ -374,6 +392,8 @@ public class Toast { params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + + mPackageName = packageName; } /** @@ -382,7 +402,7 @@ public class Toast { @Override public void show(IBinder windowToken) { if (localLOGV) Log.v(TAG, "SHOW: " + this); - mHandler.obtainMessage(0, windowToken).sendToTarget(); + mHandler.obtainMessage(SHOW, windowToken).sendToTarget(); } /** @@ -391,7 +411,12 @@ public class Toast { @Override public void hide() { if (localLOGV) Log.v(TAG, "HIDE: " + this); - mHandler.post(mHide); + mHandler.obtainMessage(HIDE).sendToTarget(); + } + + public void cancel() { + if (localLOGV) Log.v(TAG, "CANCEL: " + this); + mHandler.obtainMessage(CANCEL).sendToTarget(); } public void handleShow(IBinder windowToken) { diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 479b3b7a7a71..d49d433d665d 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -593,9 +593,6 @@ public class LockPatternUtils { setCredentialRequiredToDecrypt(false); } - getDevicePolicyManager().setActivePasswordState( - DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle); - onAfterChangingPassword(userHandle); } @@ -642,6 +639,7 @@ public class LockPatternUtils { + MIN_LOCK_PATTERN_SIZE + " dots long."); } + setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId); DevicePolicyManager dpm = getDevicePolicyManager(); @@ -658,9 +656,6 @@ public class LockPatternUtils { setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId); - setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); - dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, - pattern.size(), 0, 0, 0, 0, 0, 0, userId); onAfterChangingPassword(userId); } catch (RemoteException re) { Log.e(TAG, "Couldn't save lock pattern " + re); @@ -863,9 +858,9 @@ public class LockPatternUtils { + "of length " + MIN_LOCK_PASSWORD_SIZE); } + final int computedQuality = computePasswordQuality(password); + setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); getLockSettings().setLockPassword(password, savedPassword, userHandle); - getLockSettings().setSeparateProfileChallengeEnabled(userHandle, true, null); - int computedQuality = computePasswordQuality(password); // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM @@ -883,40 +878,6 @@ public class LockPatternUtils { } } - setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); - if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { - int letters = 0; - int uppercase = 0; - int lowercase = 0; - int numbers = 0; - int symbols = 0; - int nonletter = 0; - for (int i = 0; i < password.length(); i++) { - char c = password.charAt(i); - if (c >= 'A' && c <= 'Z') { - letters++; - uppercase++; - } else if (c >= 'a' && c <= 'z') { - letters++; - lowercase++; - } else if (c >= '0' && c <= '9') { - numbers++; - nonletter++; - } else { - symbols++; - nonletter++; - } - } - dpm.setActivePasswordState(Math.max(quality, computedQuality), - password.length(), letters, uppercase, lowercase, - numbers, symbols, nonletter, userHandle); - } else { - // The password is not anything. - dpm.setActivePasswordState( - DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - 0, 0, 0, 0, 0, 0, 0, userHandle); - } - // Add the password to the password history. We assume all // password hashes have the same length for simplicity of implementation. String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp index 6b634dfbef3e..4150636cae12 100644 --- a/core/jni/android_view_PointerIcon.cpp +++ b/core/jni/android_view_PointerIcon.cpp @@ -78,6 +78,9 @@ status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobj status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj, PointerIcon* outPointerIcon) { + if (!pointerIconObj) { + return BAD_VALUE; + } outPointerIcon->style = env->GetIntField(pointerIconObj, gPointerIconClassInfo.mType); outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX); outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY); diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 203d2474fca1..fbcb62a3a8af 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -927,6 +927,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPatternInternal(pattern, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); + notifyPasswordChanged(userId); } } @@ -941,6 +942,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); + notifyActivePasswordMetricsAvailable(null, userId); return; } @@ -990,6 +992,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPasswordInternal(password, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); + notifyPasswordChanged(userId); } } @@ -1003,6 +1006,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); + notifyActivePasswordMetricsAvailable(null, userId); return; } @@ -1412,6 +1416,7 @@ public class LockSettingsService extends ILockSettings.Stub { // migrate credential to GateKeeper credentialUtil.setCredential(credential, null, userId); if (!hasChallenge) { + notifyActivePasswordMetricsAvailable(credential, userId); return VerifyCredentialResponse.OK; } // Fall through to get the auth token. Technically this should never happen, @@ -1451,6 +1456,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (progressCallback != null) { progressCallback.onCredentialVerified(); } + notifyActivePasswordMetricsAvailable(credential, userId); unlockKeystore(credential, userId); Slog.i(TAG, "Unlocking user " + userId + @@ -1474,6 +1480,60 @@ public class LockSettingsService extends ILockSettings.Stub { return response; } + private void notifyActivePasswordMetricsAvailable(final String password, int userId) { + final int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId); + + // Asynchronous to avoid dead lock + mHandler.post(new Runnable() { + @Override + public void run() { + int length = 0; + int letters = 0; + int uppercase = 0; + int lowercase = 0; + int numbers = 0; + int symbols = 0; + int nonletter = 0; + if (password != null) { + length = password.length(); + for (int i = 0; i < length; i++) { + char c = password.charAt(i); + if (c >= 'A' && c <= 'Z') { + letters++; + uppercase++; + } else if (c >= 'a' && c <= 'z') { + letters++; + lowercase++; + } else if (c >= '0' && c <= '9') { + numbers++; + nonletter++; + } else { + symbols++; + nonletter++; + } + } + } + DevicePolicyManager dpm = (DevicePolicyManager) + mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + dpm.setActivePasswordState(quality, length, letters, uppercase, lowercase, numbers, + symbols, nonletter, userId); + } + }); + } + + /** + * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before + * reporting the password changed. + */ + private void notifyPasswordChanged(int userId) { + // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering + mHandler.post(() -> { + DevicePolicyManager dpm = (DevicePolicyManager) + mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + dpm.reportPasswordChanged(userId); + }); + } + @Override public boolean checkVoldPassword(int userId) throws RemoteException { if (!mFirstCallToVold) { diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 74095acca16a..719ce7618fd0 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -25,6 +25,7 @@ import android.view.Display; import com.android.internal.inputmethod.InputMethodSubtypeHandle; import com.android.internal.os.SomeArgs; import com.android.internal.R; +import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.DisplayThread; import com.android.server.LocalServices; @@ -1705,6 +1706,7 @@ public class InputManagerService extends IInputManager.Stub // Binder call @Override public void setCustomPointerIcon(PointerIcon icon) { + Preconditions.checkNotNull(icon); nativeSetCustomPointerIcon(mPtr, icon); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3bd533d03628..03612ab67c8f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1646,9 +1646,11 @@ public class PackageManagerService extends IPackageManager.Stub { } // Now that we successfully installed the package, grant runtime - // permissions if requested before broadcasting the install. - if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion - >= Build.VERSION_CODES.M) { + // permissions if requested before broadcasting the install. Also + // for legacy apps in permission review mode we clear the permission + // review flag which is used to emulate runtime permissions for + // legacy apps. + if (grantPermissions) { grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions); } @@ -1885,11 +1887,6 @@ public class PackageManagerService extends IPackageManager.Stub { for (int userId : userIds) { grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions); } - - // We could have touched GID membership, so flush out packages.list - synchronized (mPackages) { - mSettings.writePackageListLPr(); - } } private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId, @@ -1904,6 +1901,9 @@ public class PackageManagerService extends IPackageManager.Stub { final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED | PackageManager.FLAG_PERMISSION_POLICY_FIXED; + final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion + >= Build.VERSION_CODES.M; + for (String permission : pkg.requestedPermissions) { final BasePermission bp; synchronized (mPackages) { @@ -1913,9 +1913,18 @@ public class PackageManagerService extends IPackageManager.Stub { && (grantedPermissions == null || ArrayUtils.contains(grantedPermissions, permission))) { final int flags = permissionsState.getPermissionFlags(permission, userId); - // Installer cannot change immutable permissions. - if ((flags & immutableFlags) == 0) { - grantRuntimePermission(pkg.packageName, permission, userId); + if (supportsRuntimePermissions) { + // Installer cannot change immutable permissions. + if ((flags & immutableFlags) == 0) { + grantRuntimePermission(pkg.packageName, permission, userId); + } + } else if (mPermissionReviewRequired) { + // In permission review mode we clear the review flag when we + // are asked to install the app with all permissions granted. + if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { + updatePermissionFlags(permission, pkg.packageName, + PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0 /*value*/, userId); + } } } } @@ -10108,12 +10117,30 @@ public class PackageManagerService extends IPackageManager.Stub { int flags = permissionState != null ? permissionState.getFlags() : 0; if (origPermissions.hasRuntimePermission(bp.name, userId)) { - if (permissionsState.grantRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - // If we cannot put the permission as it was, we have to write. + // Don't propagate the permission in a permission review mode if + // the former was revoked, i.e. marked to not propagate on upgrade. + // Note that in a permission review mode install permissions are + // represented as constantly granted runtime ones since we need to + // keep a per user state associated with the permission. Also the + // revoke on upgrade flag is no longer applicable and is reset. + final boolean revokeOnUpgrade = (flags & PackageManager + .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0; + if (revokeOnUpgrade) { + flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; + // Since we changed the flags, we have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } + if (!mPermissionReviewRequired || !revokeOnUpgrade) { + 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); + } + } + // If the app supports runtime permissions no need for a review. if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) && appSupportsRuntimePermissions diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 2f72a5cd1ab5..88cfce8023af 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1462,7 +1462,11 @@ static void nativeSetCustomPointerIcon(JNIEnv* env, jclass /* clazz */, NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); PointerIcon pointerIcon; - android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon); + status_t result = android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon); + if (result) { + jniThrowRuntimeException(env, "Failed to load custom pointer icon."); + return; + } SpriteIcon spriteIcon; pointerIcon.bitmap.copyTo(&spriteIcon.bitmap, kN32_SkColorType); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 96331e83dd31..f23378cf03f8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2273,10 +2273,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, "failed-password-attempts"); } - if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 + // Don't save metrics for FBE devices + if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() + && (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0 - || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) { + || policy.mActivePasswordSymbols != 0 + || policy.mActivePasswordNonLetter != 0)) { out.startTag(null, "active-password"); out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality)); out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength)); @@ -2369,6 +2372,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { JournaledFile journal = makeJournaledFile(userHandle); FileInputStream stream = null; File file = journal.chooseForRead(); + boolean needsRewrite = false; try { stream = new FileInputStream(file); XmlPullParser parser = Xml.newPullParser(); @@ -2455,23 +2459,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("password-owner".equals(tag)) { policy.mPasswordOwner = Integer.parseInt( parser.getAttributeValue(null, "value")); - } else if ("active-password".equals(tag)) { - policy.mActivePasswordQuality = Integer.parseInt( - parser.getAttributeValue(null, "quality")); - policy.mActivePasswordLength = Integer.parseInt( - parser.getAttributeValue(null, "length")); - policy.mActivePasswordUpperCase = Integer.parseInt( - parser.getAttributeValue(null, "uppercase")); - policy.mActivePasswordLowerCase = Integer.parseInt( - parser.getAttributeValue(null, "lowercase")); - policy.mActivePasswordLetters = Integer.parseInt( - parser.getAttributeValue(null, "letters")); - policy.mActivePasswordNumeric = Integer.parseInt( - parser.getAttributeValue(null, "numeric")); - policy.mActivePasswordSymbols = Integer.parseInt( - parser.getAttributeValue(null, "symbols")); - policy.mActivePasswordNonLetter = Integer.parseInt( - parser.getAttributeValue(null, "nonletter")); } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { @@ -2488,6 +2475,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { policy.mInitBundle = PersistableBundle.restoreFromXml(parser); + } else if ("active-password".equals(tag)) { + if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) { + // Remove this from FBE devices + needsRewrite = true; + } else { + policy.mActivePasswordQuality = Integer.parseInt( + parser.getAttributeValue(null, "quality")); + policy.mActivePasswordLength = Integer.parseInt( + parser.getAttributeValue(null, "length")); + policy.mActivePasswordUpperCase = Integer.parseInt( + parser.getAttributeValue(null, "uppercase")); + policy.mActivePasswordLowerCase = Integer.parseInt( + parser.getAttributeValue(null, "lowercase")); + policy.mActivePasswordLetters = Integer.parseInt( + parser.getAttributeValue(null, "letters")); + policy.mActivePasswordNumeric = Integer.parseInt( + parser.getAttributeValue(null, "numeric")); + policy.mActivePasswordSymbols = Integer.parseInt( + parser.getAttributeValue(null, "symbols")); + policy.mActivePasswordNonLetter = Integer.parseInt( + parser.getAttributeValue(null, "nonletter")); + } } else { Slog.w(LOG_TAG, "Unknown tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -2510,29 +2519,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Generate a list of admins from the admin map policy.mAdminList.addAll(policy.mAdminMap.values()); - // Validate that what we stored for the password quality matches - // sufficiently what is currently set. Note that this is only - // a sanity check in case the two get out of sync; this should - // never normally happen. - final long identity = mInjector.binderClearCallingIdentity(); - try { - int actualPasswordQuality = mLockPatternUtils.getActivePasswordQuality(userHandle); - if (actualPasswordQuality < policy.mActivePasswordQuality) { - Slog.w(LOG_TAG, "Active password quality 0x" - + Integer.toHexString(policy.mActivePasswordQuality) - + " does not match actual quality 0x" - + Integer.toHexString(actualPasswordQuality)); - policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - policy.mActivePasswordLength = 0; - policy.mActivePasswordUpperCase = 0; - policy.mActivePasswordLowerCase = 0; - policy.mActivePasswordLetters = 0; - policy.mActivePasswordNumeric = 0; - policy.mActivePasswordSymbols = 0; - policy.mActivePasswordNonLetter = 0; - } - } finally { - mInjector.binderRestoreCallingIdentity(identity); + // Might need to upgrade the file by rewriting it + if (needsRewrite) { + saveSettingsLocked(userHandle); } validatePasswordOwnerLocked(policy); @@ -3758,6 +3747,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean isActivePasswordSufficientForUserLocked( DevicePolicyData policy, int userHandle, boolean parent) { + enforceUserUnlocked(userHandle, parent); + final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent); if (policy.mActivePasswordQuality < requiredPasswordQuality) { return false; @@ -4832,40 +4823,66 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceFullCrossUsersPermission(userHandle); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.BIND_DEVICE_ADMIN, null); + + // If the managed profile doesn't have a separate password, set the metrics to default + if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) { + quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + length = 0; + letters = 0; + uppercase = 0; + lowercase = 0; + numbers = 0; + symbols = 0; + nonletter = 0; + } + + validateQualityConstant(quality); + DevicePolicyData policy = getUserData(userHandle); + synchronized (this) { + policy.mActivePasswordQuality = quality; + policy.mActivePasswordLength = length; + policy.mActivePasswordLetters = letters; + policy.mActivePasswordLowerCase = lowercase; + policy.mActivePasswordUpperCase = uppercase; + policy.mActivePasswordNumeric = numbers; + policy.mActivePasswordSymbols = symbols; + policy.mActivePasswordNonLetter = nonletter; + } + } + + @Override + public void reportPasswordChanged(int userId) { + if (!mHasFeature) { + return; + } + enforceFullCrossUsersPermission(userId); // Managed Profile password can only be changed when it has a separate challenge. - if (!isSeparateProfileChallengeEnabled(userHandle)) { - enforceNotManagedProfile(userHandle, "set the active password"); + if (!isSeparateProfileChallengeEnabled(userId)) { + enforceNotManagedProfile(userId, "set the active password"); } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - validateQualityConstant(quality); - DevicePolicyData policy = getUserData(userHandle); + DevicePolicyData policy = getUserData(userId); long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { - policy.mActivePasswordQuality = quality; - policy.mActivePasswordLength = length; - policy.mActivePasswordLetters = letters; - policy.mActivePasswordLowerCase = lowercase; - policy.mActivePasswordUpperCase = uppercase; - policy.mActivePasswordNumeric = numbers; - policy.mActivePasswordSymbols = symbols; - policy.mActivePasswordNonLetter = nonletter; policy.mFailedPasswordAttempts = 0; - saveSettingsLocked(userHandle); - updatePasswordExpirationsLocked(userHandle); - setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false); + saveSettingsLocked(userId); + updatePasswordExpirationsLocked(userId); + setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false); // Send a broadcast to each profile using this password as its primary unlock. sendAdminCommandForLockscreenPoliciesLocked( DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userId); } - removeCaApprovalsIfNeeded(userHandle); + removeCaApprovalsIfNeeded(userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -6454,6 +6471,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "User must be running and unlocked"); } + private void enforceUserUnlocked(int userId, boolean parent) { + if (parent) { + enforceUserUnlocked(getProfileParentId(userId)); + } else { + enforceUserUnlocked(userId); + } + } + private void enforceManageUsers() { final int callingUid = mInjector.binderGetCallingUid(); if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 0de6b7790856..05071ad2eee7 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -162,6 +162,8 @@ public final class SystemServer { "com.google.android.clockwork.bluetooth.WearBluetoothService"; private static final String WEAR_WIFI_MEDIATOR_SERVICE_CLASS = "com.google.android.clockwork.wifi.WearWifiMediatorService"; + private static final String WEAR_CELLULAR_MEDIATOR_SERVICE_CLASS = + "com.google.android.clockwork.cellular.WearCellularMediatorService"; private static final String WEAR_TIME_SERVICE_CLASS = "com.google.android.clockwork.time.WearTimeService"; private static final String ACCOUNT_SERVICE_CLASS = @@ -1186,6 +1188,9 @@ public final class SystemServer { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS); mSystemServiceManager.startService(WEAR_WIFI_MEDIATOR_SERVICE_CLASS); + if (SystemProperties.getBoolean("config.enable_cellmediator", false)) { + mSystemServiceManager.startService(WEAR_CELLULAR_MEDIATOR_SERVICE_CLASS); + } if (!disableNonCoreServices) { mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS); } |