Make printing framework encryption-aware.

Only create UserState objects when a user has been unlocked, meaning
we can connect to the spooler.  Ignore package events that occur
while a user is locked, since we'll kick off updateIfNeededLocked()
when that user is eventually unlocked.

In all other cases, throw if someone tries obtaining UserState for
a still-locked user.  This should help catch any edge cases in the
system, and communicate clearly through public APIs that printing
isn't available until the user is unlocked.

Bug: 26246836
Change-Id: If15744621890baee206d355484fe20933afc65d8
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c5adafe..ddd16e2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -852,9 +852,14 @@
      * @param user to retrieve the unlocked state for.
      */
     public boolean isUserUnlocked(UserHandle user) {
+        return isUserUnlocked(user.getIdentifier());
+    }
+
+    /** {@hide} */
+    public boolean isUserUnlocked(int userId) {
         try {
-            return ActivityManagerNative.getDefault().isUserRunning(
-                    user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
+            return ActivityManagerNative.getDefault().isUserRunning(userId,
+                    ActivityManager.FLAG_AND_UNLOCKED);
         } catch (RemoteException e) {
             return false;
         }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 946b233..6f8f8eb 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -336,7 +336,7 @@
     }
 
     private void onPackageBroadcastReceived(Intent intent, int userId) {
-        if (!isUserRunningAndUnlocked(userId)) return;
+        if (!mUserManager.isUserUnlocked(userId)) return;
 
         final String action = intent.getAction();
         boolean added = false;
@@ -417,7 +417,7 @@
      * Refresh the masked state for all profiles under the given user.
      */
     private void refreshProfileWidgetsMaskedState(int userId) {
-        if (!isUserRunningAndUnlocked(userId)) return;
+        if (!mUserManager.isUserUnlocked(userId)) return;
         List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
         if (profiles != null) {
             for (int i = 0; i < profiles.size(); i++) {
@@ -431,7 +431,7 @@
      * Mask/unmask widgets in the given profile, depending on the quiet state of the profile.
      */
     private void refreshWidgetMaskedState(int profileId) {
-        if (!isUserRunningAndUnlocked(profileId)) return;
+        if (!mUserManager.isUserUnlocked(profileId)) return;
         final long identity = Binder.clearCallingIdentity();
         try {
             UserInfo user  = mUserManager.getUserInfo(profileId);
@@ -481,7 +481,7 @@
     }
 
     private void ensureGroupStateLoadedLocked(int userId) {
-        if (!isUserRunningAndUnlocked(userId)) {
+        if (!mUserManager.isUserUnlocked(userId)) {
             throw new IllegalStateException(
                     "User " + userId + " must be unlocked for widgets to be available");
         }
@@ -2512,15 +2512,6 @@
         mWidgetPackages.clear();
     }
 
-    private boolean isUserRunningAndUnlocked(int userId) {
-        if (userId == UserHandle.USER_NULL) {
-            return false;
-        } else {
-            return mContext.getSystemService(ActivityManager.class)
-                    .isUserRunningAndUnlocked(userId);
-        }
-    }
-
     @Override
     public boolean isBoundWidgetPackage(String packageName, int userId) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 0a8c014..f18617e 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -77,8 +77,8 @@
     }
 
     @Override
-    public void onStartUser(int userHandle) {
-        mPrintManagerImpl.handleUserStarted(userHandle);
+    public void onUnlockUser(int userHandle) {
+        mPrintManagerImpl.handleUserUnlocked(userHandle);
     }
 
     @Override
@@ -473,14 +473,11 @@
                 public void onChange(boolean selfChange, Uri uri, int userId) {
                     if (enabledPrintServicesUri.equals(uri)) {
                         synchronized (mLock) {
-                            if (userId != UserHandle.USER_ALL) {
-                                UserState userState = getOrCreateUserStateLocked(userId);
-                                userState.updateIfNeededLocked();
-                            } else {
-                                final int userCount = mUserStates.size();
-                                for (int i = 0; i < userCount; i++) {
-                                    UserState userState = mUserStates.valueAt(i);
-                                    userState.updateIfNeededLocked();
+                            final int userCount = mUserStates.size();
+                            for (int i = 0; i < userCount; i++) {
+                                if (userId == UserHandle.USER_ALL
+                                        || userId == mUserStates.keyAt(i)) {
+                                    mUserStates.valueAt(i).updateIfNeededLocked();
                                 }
                             }
                         }
@@ -496,6 +493,7 @@
             PackageMonitor monitor = new PackageMonitor() {
                 @Override
                 public void onPackageModified(String packageName) {
+                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
                     synchronized (mLock) {
                         // A background user/profile's print jobs are running but there is
                         // no UI shown. Hence, if the packages of such a user change we need
@@ -517,6 +515,7 @@
 
                 @Override
                 public void onPackageRemoved(String packageName, int uid) {
+                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
                     synchronized (mLock) {
                         // A background user/profile's print jobs are running but there is
                         // no UI shown. Hence, if the packages of such a user change we need
@@ -544,6 +543,7 @@
                 @Override
                 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
                         int uid, boolean doit) {
+                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return false;
                     synchronized (mLock) {
                         // A background user/profile's print jobs are running but there is
                         // no UI shown. Hence, if the packages of such a user change we need
@@ -574,6 +574,8 @@
 
                 @Override
                 public void onPackageAdded(String packageName, int uid) {
+                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
+
                     // A background user/profile's print jobs are running but there is
                     // no UI shown. Hence, if the packages of such a user change we need
                     // to handle it as the change may affect ongoing print jobs.
@@ -634,6 +636,11 @@
         }
 
         private UserState getOrCreateUserStateLocked(int userId) {
+            if (!mUserManager.isUserUnlocked(userId)) {
+                throw new IllegalStateException(
+                        "User " + userId + " must be unlocked for printing to be available");
+            }
+
             UserState userState = mUserStates.get(userId);
             if (userState == null) {
                 userState = new UserState(mContext, userId, mLock);
@@ -642,7 +649,7 @@
             return userState;
         }
 
-        private void handleUserStarted(final int userId) {
+        private void handleUserUnlocked(final int userId) {
             // This code will touch the remote print spooler which
             // must be called off the main thread, so post the work.
             BackgroundThread.getHandler().post(new Runnable() {