diff --git a/core/java/android/view/AccessibilityManagerInternal.java b/core/java/android/view/AccessibilityManagerInternal.java new file mode 100644 index 0000000000000..7bb2dc510222a --- /dev/null +++ b/core/java/android/view/AccessibilityManagerInternal.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +/** + * Accessibility manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class AccessibilityManagerInternal { + + /** + * Queries if the accessibility manager service permits setting + * a non-default encryption password. + */ + public abstract boolean isNonDefaultEncryptionPasswordAllowed(); +} diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 16fa88edddcd1..2b7af4b78e922 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -877,6 +877,30 @@ public class LockPatternUtils { } } + /** + * Gets whether the device is encrypted. + * + * @return Whether the device is encrypted. + */ + public static boolean isDeviceEncrypted() { + IMountService mountService = IMountService.Stub.asInterface( + ServiceManager.getService("mount")); + try { + return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE + && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT; + } catch (RemoteException re) { + Log.e(TAG, "Error getting encryption state", re); + } + return true; + } + + /** + * Clears the encryption password. + */ + public void clearEncryptionPassword() { + updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); + } + /** * Retrieves the quality mode we're in. * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index be3fc47ef07fd..1253bc7c74535 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -67,6 +67,7 @@ import android.util.Pools.Pool; import android.util.Pools.SimplePool; import android.util.Slog; import android.util.SparseArray; +import android.view.AccessibilityManagerInternal; import android.view.Display; import android.view.IWindow; import android.view.InputDevice; @@ -91,6 +92,7 @@ import android.view.accessibility.IAccessibilityManagerClient; import com.android.internal.R; import com.android.internal.content.PackageMonitor; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import org.xmlpull.v1.XmlPullParserException; @@ -202,6 +204,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final UserManager mUserManager; + private final LockPatternUtils mLockPatternUtils; + private int mCurrentUserId = UserHandle.USER_OWNER; //TODO: Remove this hack @@ -225,9 +229,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mSecurityPolicy = new SecurityPolicy(); mMainHandler = new MainHandler(mContext.getMainLooper()); + mLockPatternUtils = new LockPatternUtils(context); registerBroadcastReceivers(); new AccessibilityContentObserver(mMainHandler).register( context.getContentResolver()); + LocalServices.addService(AccessibilityManagerInternal.class, new LocalService()); } private UserState getUserStateLocked(int userId) { @@ -1294,6 +1300,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { updateTouchExplorationLocked(userState); updateEnhancedWebAccessibilityLocked(userState); updateDisplayColorAdjustmentSettingsLocked(userState); + updateEncryptionState(userState); scheduleUpdateInputFilter(userState); scheduleUpdateClientsIfNeededLocked(userState); } @@ -1570,6 +1577,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId); } + private void updateEncryptionState(UserState userState) { + if (userState.mUserId != UserHandle.USER_OWNER) { + return; + } + if (hasRunningServicesLocked(userState) && LockPatternUtils.isDeviceEncrypted()) { + // If there are running accessibility services we do not have encryption as + // the user needs the accessibility layer to be running to authenticate. + mLockPatternUtils.clearEncryptionPassword(); + } + } + + private boolean hasRunningServicesLocked(UserState userState) { + return !userState.mBoundServices.isEmpty() || !userState.mBindingServices.isEmpty(); + } + private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) { IBinder windowToken = mGlobalWindowTokens.get(windowId); if (windowToken == null) { @@ -3883,4 +3905,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } } + + private final class LocalService extends AccessibilityManagerInternal { + @Override + public boolean isNonDefaultEncryptionPasswordAllowed() { + synchronized (mLock) { + UserState userState = getCurrentUserStateLocked(); + return !hasRunningServicesLocked(userState); + } + } + } } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 7f24d07debce7..b0535b3c2a4c2 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -63,6 +63,7 @@ import android.util.AttributeSet; import android.util.Slog; import android.util.Xml; +import android.view.AccessibilityManagerInternal; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IMediaContainerService; @@ -557,6 +558,8 @@ class MountService extends IMountService.Stub private final Handler mHandler; + private final AccessibilityManagerInternal mAccessibilityManagerInternal; + void waitForAsecScan() { waitForLatch(mAsecsScanned); } @@ -1454,6 +1457,9 @@ class MountService extends IMountService.Stub hthread.start(); mHandler = new MountServiceHandler(hthread.getLooper()); + mAccessibilityManagerInternal = LocalServices.getService( + AccessibilityManagerInternal.class); + // Watch for user changes final IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_ADDED); @@ -2254,8 +2260,15 @@ class MountService extends IMountService.Stub final NativeDaemonEvent event; try { + // The accessibility layer may veto having a non-default encryption + // password because if there are enabled accessibility services the + // user cannot authenticate as the latter need access to the data. + if (!TextUtils.isEmpty(password) + && !mAccessibilityManagerInternal.isNonDefaultEncryptionPasswordAllowed()) { + return getEncryptionState(); + } event = mConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type], - new SensitiveArg(toHex(password))); + new SensitiveArg(toHex(password))); return Integer.parseInt(event.getMessage()); } catch (NativeDaemonConnectorException e) { // Encryption failed @@ -2302,7 +2315,7 @@ class MountService extends IMountService.Stub * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager. */ @Override - public int getPasswordType() throws RemoteException { + public int getPasswordType() { waitForReady();