Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86b1df23 authored by Svetoslav's avatar Svetoslav
Browse files

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
parent 105f6ceb
Loading
Loading
Loading
Loading
+42 −6
Original line number Diff line number Diff line
@@ -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.
     * <p>
@@ -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.
     * <p>
     * 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.
     * </p>
     *
     * @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);
            }
        }

+4 −6
Original line number Diff line number Diff line
@@ -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.*;


/**
@@ -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
            }
+9 −9
Original line number Diff line number Diff line
@@ -2,8 +2,8 @@
**
** 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. 
** 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
@@ -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);
}
+1 −1
Original line number Diff line number Diff line
@@ -255,7 +255,7 @@ public final class ContentService extends IContentService.Stub {
            for (int i=0; i<numCalls; i++) {
                ObserverCall oc = calls.get(i);
                try {
                    oc.mObserver.onChange(oc.mSelfChange, uri);
                    oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
                    }
+58 −103
Original line number Diff line number Diff line
@@ -17,14 +17,14 @@
package com.android.server.print;

import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -81,10 +81,13 @@ public final class PrintManagerService extends SystemService {
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
            mPrintManagerImpl.systemRunning();
    public void onStartUser(int userHandle) {
        mPrintManagerImpl.handleUserStarted(userHandle);
    }

    @Override
    public void onStopUser(int userHandle) {
        mPrintManagerImpl.handleUserStopped(userHandle);
    }

    class PrintManagerImpl extends IPrintManager.Stub {
@@ -101,9 +104,7 @@ public final class PrintManagerService extends SystemService {

        private final UserManager mUserManager;

        private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();

        private int mCurrentUserId = UserHandle.USER_OWNER;
        private final SparseArray<UserState> 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,14 +469,22 @@ 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();
                            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();
                                }
                            }
                        }
                    }
                }
            };

            mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
@@ -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 = getOrCreateUserStateLocked(userId);
                userState.updateIfNeededLocked();
                } else {
                    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);