Add account locked notification when users are encrypted
Fixes bug 26407543
Change-Id: Ic66669cd5f75b5fa41449e33133439752cef112b
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 4e4552d..b07e36a 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -39,4 +39,5 @@
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
void requireStrongAuth(int strongAuthReason, int userId);
+ void systemReady();
}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a276854..cab257b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4190,4 +4190,12 @@
<string name="new_sms_notification_title">You have new messages</string>
<!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
<string name="new_sms_notification_content">Open SMS app to view</string>
+
+ <!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="user_encrypted_title">Device encrypted</string>
+ <!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="user_encrypted_message">Some functions might not be available</string>
+ <!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="user_encrypted_detail">Touch to continue</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 81705b4..253355c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2505,4 +2505,10 @@
<java-symbol type="string" name="new_sms_notification_content" />
<java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
+
+ <!-- Encryption notification while accounts are locked by credential encryption -->
+ <java-symbol type="string" name="user_encrypted_title" />
+ <java-symbol type="string" name="user_encrypted_message" />
+ <java-symbol type="string" name="user_encrypted_detail" />
+
</resources>
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f6f05fe..e9f0a7a 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,11 +17,12 @@
package com.android.server;
import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
import android.app.trust.IStrongAuthTracker;
-import android.app.trust.ITrustManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -30,6 +31,8 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
+
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
import static android.content.Context.USER_SERVICE;
import static android.Manifest.permission.READ_CONTACTS;
@@ -40,7 +43,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -70,19 +72,27 @@
* @hide
*/
public class LockSettingsService extends ILockSettings.Stub {
-
- private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
-
private static final String TAG = "LockSettingsService";
+ private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
+ private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
+ private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
+ private static final boolean DEBUG = false;
private final Context mContext;
-
private final LockSettingsStorage mStorage;
private final LockSettingsStrongAuth mStrongAuth;
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
private IGateKeeperService mGateKeeperService;
+ private NotificationManager mNotificationManager;
+ private UserManager mUserManager;
+
+ static {
+ // Just launch the home screen, which happens anyway
+ ACTION_NULL = new Intent(Intent.ACTION_MAIN);
+ ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
+ }
private interface CredentialUtil {
void setCredential(String credential, String savedCredential, int userId)
@@ -91,6 +101,42 @@
String adjustForKeystore(String credential);
}
+ // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
+ // devices. The most basic of these is to show/hide notifications about missing features until
+ // the user unlocks the account and credential-encrypted storage is available.
+ public static final class Lifecycle extends SystemService {
+ private LockSettingsService mLockSettingsService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mLockSettingsService = new LockSettingsService(getContext());
+ publishBinderService("lock_settings", mLockSettingsService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
+ } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+ // TODO
+ }
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mLockSettingsService.onUnlockUser(userHandle);
+ }
+
+ @Override
+ public void onCleanupUser(int userHandle) {
+ mLockSettingsService.onCleanupUser(userHandle);
+ }
+ }
+
public LockSettingsService(Context context) {
mContext = context;
mStrongAuth = new LockSettingsStrongAuth(context);
@@ -117,6 +163,71 @@
}
}
});
+ mNotificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ }
+
+ /**
+ * If the account is credential-encrypted, show notification requesting the user to unlock
+ * the device.
+ */
+ private void maybeShowEncryptionNotification(UserHandle userHandle) {
+ if (UserHandle.ALL.equals(userHandle)) {
+ final List<UserInfo> users = mUserManager.getUsers();
+ for (int i = 0; i < users.size(); i++) {
+ UserHandle user = users.get(i).getUserHandle();
+ if (!mUserManager.isUserUnlocked(user)) {
+ showEncryptionNotification(user);
+ }
+ }
+ } else if (!mUserManager.isUserUnlocked(userHandle)){
+ showEncryptionNotification(userHandle);
+ }
+ }
+
+ private void showEncryptionNotification(UserHandle user) {
+ if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
+ Resources r = mContext.getResources();
+ CharSequence title = r.getText(
+ com.android.internal.R.string.user_encrypted_title);
+ CharSequence message = r.getText(
+ com.android.internal.R.string.user_encrypted_message);
+ CharSequence detail = r.getText(
+ com.android.internal.R.string.user_encrypted_detail);
+
+ PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(title)
+ .setDefaults(0) // please be quiet
+ .setPriority(Notification.PRIORITY_MAX)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(message)
+ .setContentInfo(detail)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setContentIntent(intent)
+ .build();
+ mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
+ }
+
+ public void hideEncryptionNotification(UserHandle userHandle) {
+ if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
+ mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
+ }
+
+ public void onCleanupUser(int userId) {
+ hideEncryptionNotification(new UserHandle(userId));
+ }
+
+ public void onUnlockUser(int userHandle) {
+ hideEncryptionNotification(new UserHandle(userHandle));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -144,6 +255,7 @@
}
};
+ @Override // binder interface
public void systemReady() {
migrateOldData();
try {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9f320e4..254a37a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -68,6 +68,7 @@
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
import com.android.server.lights.LightsService;
+import com.android.internal.widget.ILockSettings;
import com.android.server.media.MediaRouterService;
import com.android.server.media.MediaSessionService;
import com.android.server.media.MediaResourceMonitorService;
@@ -143,6 +144,8 @@
"com.android.server.ethernet.EthernetService";
private static final String JOB_SCHEDULER_SERVICE_CLASS =
"com.android.server.job.JobSchedulerService";
+ private static final String LOCK_SETTINGS_SERVICE_CLASS =
+ "com.android.server.LockSettingsService$Lifecycle";
private static final String MOUNT_SERVICE_CLASS =
"com.android.server.MountService$Lifecycle";
private static final String SEARCH_MANAGER_SERVICE_CLASS =
@@ -607,7 +610,7 @@
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
TextServicesManagerService tsms = null;
- LockSettingsService lockSettings = null;
+ ILockSettings lockSettings = null;
AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
@@ -680,8 +683,9 @@
if (!disableNonCoreServices) {
traceBeginAndSlog("StartLockSettingsService");
try {
- lockSettings = new LockSettingsService(context);
- ServiceManager.addService("lock_settings", lockSettings);
+ mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
+ lockSettings = ILockSettings.Stub.asInterface(
+ ServiceManager.getService("lock_settings"));
} catch (Throwable e) {
reportWtf("starting LockSettingsService service", e);
}