From 86b1df234397802895771fe14cd8f2813fa43415 Mon Sep 17 00:00:00 2001 From: Svetoslav Date: Thu, 21 Aug 2014 14:22:53 -0700 Subject: [PATCH] Print services setting changes not handled for managed profiles. We keep per user settings for enabled print services which are observed to update the print manager service state. We were listening to all user changes but the handling code was not updating the state of the user whose settings changed, rather the current user. Added hidden APIs in content observer to know which user changed and now the print manager serivce handles content changes for the correct user. bug:16977006 Change-Id: I71ec88c8f3f38cb405844c13ab83695c2029eb79 --- .../android/database/ContentObserver.java | 48 +++++- .../database/CursorToBulkCursorAdaptor.java | 10 +- .../android/database/IContentObserver.aidl | 18 +- .../server/content/ContentService.java | 2 +- .../server/print/PrintManagerService.java | 161 +++++++----------- 5 files changed, 114 insertions(+), 125 deletions(-) diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java index e4fbc2846f0db..5f01e300bf425 100644 --- a/core/java/android/database/ContentObserver.java +++ b/core/java/android/database/ContentObserver.java @@ -18,6 +18,7 @@ package android.database; import android.net.Uri; import android.os.Handler; +import android.os.UserHandle; /** * Receives call backs for changes to content. @@ -129,6 +130,21 @@ public abstract class ContentObserver { onChange(selfChange); } + /** + * Dispatches a change notification to the observer. Includes the changed + * content Uri when available and also the user whose content changed. + * + * @param selfChange True if this is a self-change notification. + * @param uri The Uri of the changed content, or null if unknown. + * @param userId The user whose content changed. Can be either a specific + * user or {@link UserHandle#USER_ALL}. + * + * @hide + */ + public void onChange(boolean selfChange, Uri uri, int userId) { + onChange(selfChange, uri); + } + /** * Dispatches a change notification to the observer. *

@@ -159,25 +175,45 @@ public abstract class ContentObserver { * @param uri The Uri of the changed content, or null if unknown. */ public final void dispatchChange(boolean selfChange, Uri uri) { + dispatchChange(selfChange, uri, UserHandle.getCallingUserId()); + } + + /** + * Dispatches a change notification to the observer. Includes the changed + * content Uri when available and also the user whose content changed. + *

+ * If a {@link Handler} was supplied to the {@link ContentObserver} constructor, + * then a call to the {@link #onChange} method is posted to the handler's message queue. + * Otherwise, the {@link #onChange} method is invoked immediately on this thread. + *

+ * + * @param selfChange True if this is a self-change notification. + * @param uri The Uri of the changed content, or null if unknown. + * @param userId The user whose content changed. + */ + private void dispatchChange(boolean selfChange, Uri uri, int userId) { if (mHandler == null) { - onChange(selfChange, uri); + onChange(selfChange, uri, userId); } else { - mHandler.post(new NotificationRunnable(selfChange, uri)); + mHandler.post(new NotificationRunnable(selfChange, uri, userId)); } } + private final class NotificationRunnable implements Runnable { private final boolean mSelfChange; private final Uri mUri; + private final int mUserId; - public NotificationRunnable(boolean selfChange, Uri uri) { + public NotificationRunnable(boolean selfChange, Uri uri, int userId) { mSelfChange = selfChange; mUri = uri; + mUserId = userId; } @Override public void run() { - ContentObserver.this.onChange(mSelfChange, mUri); + ContentObserver.this.onChange(mSelfChange, mUri, mUserId); } } @@ -189,10 +225,10 @@ public abstract class ContentObserver { } @Override - public void onChange(boolean selfChange, Uri uri) { + public void onChange(boolean selfChange, Uri uri, int userId) { ContentObserver contentObserver = mContentObserver; if (contentObserver != null) { - contentObserver.dispatchChange(selfChange, uri); + contentObserver.dispatchChange(selfChange, uri, userId); } } diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java index 7dcfae2264e3c..02eddf239dca4 100644 --- a/core/java/android/database/CursorToBulkCursorAdaptor.java +++ b/core/java/android/database/CursorToBulkCursorAdaptor.java @@ -17,9 +17,7 @@ package android.database; import android.net.Uri; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; +import android.os.*; /** @@ -33,7 +31,7 @@ import android.os.RemoteException; * * {@hide} */ -public final class CursorToBulkCursorAdaptor extends BulkCursorNative +public final class CursorToBulkCursorAdaptor extends BulkCursorNative implements IBinder.DeathRecipient { private static final String TAG = "Cursor"; @@ -66,7 +64,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative // Do nothing, the far side is dead } } - + public boolean unlinkToDeath(DeathRecipient recipient) { return mRemote.asBinder().unlinkToDeath(recipient, 0); } @@ -80,7 +78,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative @Override public void onChange(boolean selfChange, Uri uri) { try { - mRemote.onChange(selfChange, uri); + mRemote.onChange(selfChange, uri, android.os.Process.myUid()); } catch (RemoteException ex) { // Do nothing, the far side is dead } diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl index 13aff058a9562..22dc9fed59c49 100644 --- a/core/java/android/database/IContentObserver.aidl +++ b/core/java/android/database/IContentObserver.aidl @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -29,5 +29,5 @@ interface IContentObserver * observed. selfUpdate is true if the update was caused by a call to * commit on the cursor that is being observed. */ - oneway void onChange(boolean selfUpdate, in Uri uri); + oneway void onChange(boolean selfUpdate, in Uri uri, int userId); } diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 64d3dc524818e..165148b7cde57 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -255,7 +255,7 @@ public final class ContentService extends IContentService.Stub { for (int i=0; i mUserStates = new SparseArray(); - - private int mCurrentUserId = UserHandle.USER_OWNER; + private final SparseArray mUserStates = new SparseArray<>(); PrintManagerImpl(Context context) { mContext = context; @@ -112,22 +113,6 @@ public final class PrintManagerService extends SystemService { registerBroadcastReceivers(); } - public void systemRunning() { - BackgroundThread.getHandler().post(new Runnable() { - @Override - public void run() { - final UserState userState; - synchronized (mLock) { - userState = getCurrentUserStateLocked(); - } - // This is the first time we switch to this user after boot, so - // now is the time to remove obsolete print jobs since they - // are from the last boot and no application would query them. - userState.removeObsoletePrintJobs(); - } - }); - } - @Override public Bundle print(String printJobName, IPrintDocumentAdapter adapter, PrintAttributes attributes, String packageName, int appId, int userId) { @@ -137,7 +122,7 @@ public final class PrintManagerService extends SystemService { final String resolvedPackageName; synchronized (mLock) { // Only the current group members can start new print jobs. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return null; } resolvedAppId = resolveCallingAppEnforcingPermissions(appId); @@ -160,7 +145,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can query for state of print jobs. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return null; } resolvedAppId = resolveCallingAppEnforcingPermissions(appId); @@ -181,7 +166,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can query for state of a print job. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return null; } resolvedAppId = resolveCallingAppEnforcingPermissions(appId); @@ -202,7 +187,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can cancel a print job. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } resolvedAppId = resolveCallingAppEnforcingPermissions(appId); @@ -223,7 +208,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can restart a print job. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } resolvedAppId = resolveCallingAppEnforcingPermissions(appId); @@ -243,7 +228,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can get enabled services. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return null; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -262,7 +247,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can get installed services. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return null; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -282,7 +267,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can create a discovery session. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -302,7 +287,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can destroy a discovery session. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -322,7 +307,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can start discovery. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -341,7 +326,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can stop discovery. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -360,7 +345,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can validate printers. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -379,7 +364,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can start printer tracking. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -398,7 +383,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can stop printer tracking. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -419,7 +404,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can add a print job listener. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } resolvedAppId = resolveCallingAppEnforcingPermissions(appId); @@ -440,7 +425,7 @@ public final class PrintManagerService extends SystemService { final UserState userState; synchronized (mLock) { // Only the current group members can remove a print job listener. - if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) { + if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { return; } userState = getOrCreateUserStateLocked(resolvedUserId); @@ -484,11 +469,19 @@ public final class PrintManagerService extends SystemService { Settings.Secure.ENABLED_PRINT_SERVICES); ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { @Override - public void onChange(boolean selfChange, Uri uri) { + public void onChange(boolean selfChange, Uri uri, int userId) { if (enabledPrintServicesUri.equals(uri)) { synchronized (mLock) { - UserState userState = getCurrentUserStateLocked(); - userState.updateIfNeededLocked(); + 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(); + } + } } } } @@ -622,27 +615,6 @@ public final class PrintManagerService extends SystemService { // package changes monitor.register(mContext, BackgroundThread.getHandler().getLooper(), UserHandle.ALL, true); - - // user changes - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_USER_SWITCHED); - intentFilter.addAction(Intent.ACTION_USER_REMOVED); - - mContext.registerReceiverAsUser(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); - } else if (Intent.ACTION_USER_REMOVED.equals(action)) { - removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); - } - } - }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); - } - - private UserState getCurrentUserStateLocked() { - return getOrCreateUserStateLocked(mCurrentUserId); } private UserState getOrCreateUserStateLocked(int userId) { @@ -654,20 +626,11 @@ public final class PrintManagerService extends SystemService { return userState; } - private void switchUser(int newUserId) { + private void handleUserStarted(int userId) { UserState userState; synchronized (mLock) { - if (newUserId == mCurrentUserId) { - return; - } - mCurrentUserId = newUserId; - userState = mUserStates.get(mCurrentUserId); - if (userState == null) { - userState = getCurrentUserStateLocked(); - userState.updateIfNeededLocked(); - } else { - userState.updateIfNeededLocked(); - } + userState = getOrCreateUserStateLocked(userId); + userState.updateIfNeededLocked(); } // This is the first time we switch to this user after boot, so // now is the time to remove obsolete print jobs since they @@ -675,18 +638,18 @@ public final class PrintManagerService extends SystemService { userState.removeObsoletePrintJobs(); } - private void removeUser(int removedUserId) { + private void handleUserStopped(int userId) { synchronized (mLock) { - UserState userState = mUserStates.get(removedUserId); + UserState userState = mUserStates.get(userId); if (userState != null) { userState.destroyLocked(); - mUserStates.remove(removedUserId); + mUserStates.remove(userId); } } } private int resolveCallingProfileParentLocked(int userId) { - if (userId != mCurrentUserId) { + if (userId != getCurrentUserId()) { final long identity = Binder.clearCallingIdentity(); try { UserInfo parent = mUserManager.getProfileParent(userId); @@ -723,28 +686,11 @@ public final class PrintManagerService extends SystemService { } private int resolveCallingUserEnforcingPermissions(int userId) { - final int callingUid = Binder.getCallingUid(); - if (callingUid == 0 || callingUid == Process.SYSTEM_UID - || callingUid == Process.SHELL_UID) { - return userId; - } - final int callingUserId = UserHandle.getUserId(callingUid); - if (callingUserId == userId) { - return userId; - } - if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL) - != PackageManager.PERMISSION_GRANTED - && mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS) - != PackageManager.PERMISSION_GRANTED) { - if (userId == UserHandle.USER_CURRENT_OR_SELF) { - return callingUserId; - } - throw new SecurityException("Call from user " + callingUserId + " as user " - + userId + " without permission INTERACT_ACROSS_USERS or " - + "INTERACT_ACROSS_USERS_FULL not allowed."); - } - if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { - return mCurrentUserId; + try { + return ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, true, true, "", null); + } catch (RemoteException re) { + // Shouldn't happen, local. } return userId; } @@ -764,6 +710,15 @@ public final class PrintManagerService extends SystemService { return null; } + private int getCurrentUserId () { + final long identity = Binder.clearCallingIdentity(); + try { + return ActivityManager.getCurrentUser(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private void showEnableInstalledPrintServiceNotification(ComponentName component, String label, int userId) { UserHandle userHandle = new UserHandle(userId);