am b34de6be: Merge "Fix adb backup for encrypted case" into lmp-dev

* commit 'b34de6be2ede2e31a79958d6a2e6c53761c92d04':
  Fix adb backup for encrypted case
diff --git a/packages/BackupRestoreConfirmation/res/values/strings.xml b/packages/BackupRestoreConfirmation/res/values/strings.xml
index 5c90fd0..3fb3fd4 100644
--- a/packages/BackupRestoreConfirmation/res/values/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values/strings.xml
@@ -44,6 +44,8 @@
     <string name="backup_enc_password_text">Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:</string>
     <!-- Text for message to user that they may optionally supply an encryption password to use for a full backup operation. -->
     <string name="backup_enc_password_optional">If you wish to encrypt the full backup data, enter a password below:</string>
+    <!-- Text for message to user that they must supply an encryption password to use for a full backup operation because their phone is locked. -->
+    <string name="backup_enc_password_required">Since your device is encrypted, you are required to encrypt your backup. Please enter a password below:</string>
 
     <!-- Text for message to user when performing a full restore operation, explaining that they must enter the password originally used to encrypt the full backup data. -->
     <string name="restore_enc_password_text">If the restore data is encrypted, please enter the password below:</string>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index 82ac8cb..c2bb90c 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -28,6 +28,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
 import android.util.Log;
 import android.util.Slog;
 import android.view.View;
@@ -182,25 +183,14 @@
         // We vary the password prompt depending on whether one is predefined, and whether
         // the device is encrypted.
         mIsEncrypted = deviceIsEncrypted();
-        if (mIsEncrypted) {
-            Log.d(TAG, "Device is encrypted: requiring encryption pw");
-            TextView pwPrompt = (TextView) findViewById(R.id.password_desc);
-            // this password is mandatory; we hide the other options during backup
-            if (layoutId == R.layout.confirm_backup) {
-                pwPrompt.setText(R.string.device_encryption_backup_text);
-                TextView tv = (TextView) findViewById(R.id.enc_password);
-                tv.setVisibility(View.GONE);
-                tv = (TextView) findViewById(R.id.enc_password_desc);
-                tv.setVisibility(View.GONE);
-            } else {
-                pwPrompt.setText(R.string.device_encryption_restore_text);
-            }
-        } else if (!haveBackupPassword()) {
+        if (!haveBackupPassword()) {
             curPwDesc.setVisibility(View.GONE);
             mCurPassword.setVisibility(View.GONE);
             if (layoutId == R.layout.confirm_backup) {
                 TextView encPwDesc = (TextView) findViewById(R.id.enc_password_desc);
-                encPwDesc.setText(R.string.backup_enc_password_optional);
+                encPwDesc.setText(mIsEncrypted
+                                  ? R.string.backup_enc_password_required
+                                  : R.string.backup_enc_password_optional);
             }
         }
 
@@ -246,8 +236,7 @@
             mDidAcknowledge = true;
 
             try {
-                CharSequence encPassword = (mIsEncrypted)
-                        ? mCurPassword.getText() : mEncPassword.getText();
+                CharSequence encPassword = mEncPassword.getText();
                 mBackupManager.acknowledgeFullBackupOrRestore(mToken,
                         allow,
                         String.valueOf(mCurPassword.getText()),
@@ -261,7 +250,10 @@
 
     boolean deviceIsEncrypted() {
         try {
-            return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE);
+            return mMountService.getEncryptionState()
+                     != IMountService.ENCRYPTION_STATE_NONE
+                && mMountService.getPasswordType()
+                     != StorageManager.CRYPT_TYPE_DEFAULT;
         } catch (Exception e) {
             // If we can't talk to the mount service we have a serious problem; fail
             // "secure" i.e. assuming that the device is encrypted.
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index cf86f23..9674ca2 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -75,6 +75,7 @@
 import android.os.WorkSource;
 import android.os.Environment.UserEnvironment;
 import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -1430,43 +1431,7 @@
         return array;
     }
 
-    // Backup password management
     boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
-        // First, on an encrypted device we require matching the device pw
-        final boolean isEncrypted;
-        try {
-            isEncrypted = (mMountService.getEncryptionState() !=
-                    IMountService.ENCRYPTION_STATE_NONE);
-            if (isEncrypted) {
-                if (DEBUG) {
-                    Slog.i(TAG, "Device encrypted; verifying against device data pw");
-                }
-                // 0 means the password validated
-                // -2 means device not encrypted
-                // Any other result is either password failure or an error condition,
-                // so we refuse the match
-                final int result = mMountService.verifyEncryptionPassword(candidatePw);
-                if (result == 0) {
-                    if (MORE_DEBUG) Slog.d(TAG, "Pw verifies");
-                    return true;
-                } else if (result != -2) {
-                    if (MORE_DEBUG) Slog.d(TAG, "Pw mismatch");
-                    return false;
-                } else {
-                    // ...else the device is supposedly not encrypted.  HOWEVER, the
-                    // query about the encryption state said that the device *is*
-                    // encrypted, so ... we may have a problem.  Log it and refuse
-                    // the backup.
-                    Slog.e(TAG, "verified encryption state mismatch against query; no match allowed");
-                    return false;
-                }
-            }
-        } catch (Exception e) {
-            // Something went wrong talking to the mount service.  This is very bad;
-            // assume that we fail password validation.
-            return false;
-        }
-
         if (mPasswordHash == null) {
             // no current password case -- require that 'currentPw' be null or empty
             if (candidatePw == null || "".equals(candidatePw)) {
@@ -1571,14 +1536,7 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "hasBackupPassword");
 
-        try {
-            return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE)
-                || (mPasswordHash != null && mPasswordHash.length() > 0);
-        } catch (Exception e) {
-            // If we can't talk to the mount service we have a serious problem; fail
-            // "secure" i.e. assuming that we require a password
-            return true;
-        }
+        return mPasswordHash != null && mPasswordHash.length() > 0;
     }
 
     private boolean backupPasswordMatches(String currentPw) {
@@ -3341,6 +3299,20 @@
         }
     }
 
+    boolean deviceIsEncrypted() {
+        try {
+            return mMountService.getEncryptionState()
+                     != IMountService.ENCRYPTION_STATE_NONE
+                && mMountService.getPasswordType()
+                     != StorageManager.CRYPT_TYPE_DEFAULT;
+        } catch (Exception e) {
+            // If we can't talk to the mount service we have a serious problem; fail
+            // "secure" i.e. assuming that the device is encrypted.
+            Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
+            return true;
+        }
+    }
+
     // Full backup task variant used for adb backup
     class PerformAdbBackupTask extends FullBackupTask {
         FullBackupEngine mBackupEngine;
@@ -3358,7 +3330,7 @@
         ArrayList<String> mPackages;
         String mCurrentPassword;
         String mEncryptPassword;
-        
+
         PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, 
                 boolean includeApks, boolean includeObbs, boolean includeShared,
                 boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
@@ -3555,6 +3527,13 @@
             PackageInfo pkg = null;
             try {
                 boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
+
+                // Only allow encrypted backups of encrypted devices
+                if (deviceIsEncrypted() && !encrypting) {
+                    Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
+                    return;
+                }
+
                 OutputStream finalOutput = ofstream;
 
                 // Verify that the given password matches the currently-active
@@ -8335,17 +8314,7 @@
                         params.observer = observer;
                         params.curPassword = curPassword;
 
-                        boolean isEncrypted;
-                        try {
-                            isEncrypted = (mMountService.getEncryptionState() !=
-                                    IMountService.ENCRYPTION_STATE_NONE);
-                            if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
-                        } catch (RemoteException e) {
-                            // couldn't contact the mount service; fail "safe" and assume encryption
-                            Slog.e(TAG, "Unable to contact mount service!");
-                            isEncrypted = true;
-                        }
-                        params.encryptPassword = (isEncrypted) ? curPassword : encPpassword;
+                        params.encryptPassword = encPpassword;
 
                         if (DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
                         mWakelock.acquire();