diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl index d7c267b5ca63b..d3d38744a1a93 100644 --- a/core/java/android/print/IPrintManager.aidl +++ b/core/java/android/print/IPrintManager.aidl @@ -143,4 +143,21 @@ interface IPrintManager { void stopPrinterStateTracking(in PrinterId printerId, int userId); void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId); + + /** + * Check if the system will bind to print services in intant app. + * + * @param userId the Id of the user the behavior should be checked for + * + * @return {@code true} iff the system will bind to print services in instant apps. + */ + boolean getBindInstantServiceAllowed(int userId); + + /** + * Set if the system will bind to print services in intant app. + * + * @param userId the Id of the user the behavior should be changed for + * @param allows iff {@code true} the system will bind to print services in instant apps + */ + void setBindInstantServiceAllowed(int userId, boolean allowed); } diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index 83d7e1666809c..06fbf9f6e1c13 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -811,6 +811,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat List resolvedActivities = getPackageManager() .queryIntentActivities(intent, 0); if (resolvedActivities.isEmpty()) { + Log.w(LOG_TAG, "Advanced options activity " + mAdvancedPrintOptionsActivity + " could " + + "not be found"); return; } diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 83a125d1fc366..dc55179bdc9e8 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -18,8 +18,12 @@ package com.android.server.print; import static android.content.pm.PackageManager.GET_SERVICES; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static android.content.pm.PackageManager.MATCH_INSTANT; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SHELL_UID; import android.annotation.NonNull; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.ComponentName; @@ -36,6 +40,8 @@ import android.os.Bundle; import android.os.Looper; import android.os.Process; import android.os.RemoteException; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; import android.print.IPrintDocumentAdapter; @@ -121,6 +127,13 @@ public final class PrintManagerService extends SystemService { registerBroadcastReceivers(); } + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + new PrintShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver); + } + @Override public Bundle print(String printJobName, IPrintDocumentAdapter adapter, PrintAttributes attributes, String packageName, int appId, int userId) { @@ -717,6 +730,46 @@ public final class PrintManagerService extends SystemService { } } + @Override + public boolean getBindInstantServiceAllowed(@UserIdInt int userId) { + int callingUid = Binder.getCallingUid(); + if (callingUid != SHELL_UID && callingUid != ROOT_UID) { + throw new SecurityException("Can only be called by uid " + SHELL_UID + + " or " + ROOT_UID); + } + + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(userId, false); + } + final long identity = Binder.clearCallingIdentity(); + try { + return userState.getBindInstantServiceAllowed(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void setBindInstantServiceAllowed(@UserIdInt int userId, boolean allowed) { + int callingUid = Binder.getCallingUid(); + if (callingUid != SHELL_UID && callingUid != ROOT_UID) { + throw new SecurityException("Can only be called by uid " + SHELL_UID + + " or " + ROOT_UID); + } + + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(userId, false); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.setBindInstantServiceAllowed(allowed); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private boolean isPrintingEnabled() { return !mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING, Binder.getCallingUserHandle()); @@ -773,7 +826,7 @@ public final class PrintManagerService extends SystemService { List installedServices = mContext.getPackageManager() .queryIntentServicesAsUser(intent, - GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING, + GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING | MATCH_INSTANT, getChangingUserId()); return installedServices != null && !installedServices.isEmpty(); @@ -988,7 +1041,7 @@ public final class PrintManagerService extends SystemService { return appId; } final int callingAppId = UserHandle.getAppId(callingUid); - if (appId == callingAppId || callingAppId == Process.SHELL_UID + if (appId == callingAppId || callingAppId == SHELL_UID || callingAppId == Process.SYSTEM_UID) { return appId; } diff --git a/services/print/java/com/android/server/print/PrintShellCommand.java b/services/print/java/com/android/server/print/PrintShellCommand.java new file mode 100644 index 0000000000000..11642e5a45e91 --- /dev/null +++ b/services/print/java/com/android/server/print/PrintShellCommand.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2018 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 + * + * 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 + * limitations under the License. + */ + +package com.android.server.print; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.RemoteException; +import android.os.ShellCommand; +import android.os.UserHandle; +import android.print.IPrintManager; + +import java.io.PrintWriter; + +/** + * Shell command implementation for the print manager service + */ +final class PrintShellCommand extends ShellCommand { + final @NonNull IPrintManager mService; + + PrintShellCommand(@NonNull IPrintManager service) { + mService = service; + } + + @Override + public int onCommand(@Nullable String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + switch (cmd) { + case "get-bind-instant-service-allowed": { + return runGetBindInstantServiceAllowed(); + } + case "set-bind-instant-service-allowed": { + return runSetBindInstantServiceAllowed(); + } + } + return -1; + } + + private int runGetBindInstantServiceAllowed() { + final Integer userId = parseUserId(); + if (userId == null) { + return -1; + } + try { + getOutPrintWriter().println( + Boolean.toString(mService.getBindInstantServiceAllowed(userId))); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return 0; + } + + private int runSetBindInstantServiceAllowed() { + final Integer userId = parseUserId(); + if (userId == null) { + return -1; + } + final String allowed = getNextArgRequired(); + if (allowed == null) { + getErrPrintWriter().println("Error: no true/false specified"); + return -1; + } + try { + mService.setBindInstantServiceAllowed(userId, Boolean.parseBoolean(allowed)); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return 0; + } + + private @Nullable Integer parseUserId() { + final String option = getNextOption(); + if (option != null) { + if (option.equals("--user")) { + return UserHandle.parseUserArg(getNextArgRequired()); + } else { + getErrPrintWriter().println("Unknown option: " + option); + return null; + } + } + return UserHandle.USER_SYSTEM; + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + pw.println("Print service commands:"); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println(" set-bind-instant-service-allowed [--user ] true|false "); + pw.println(" Set whether binding to print services provided by instant apps is " + + "allowed."); + pw.println(" get-bind-instant-service-allowed [--user ]"); + pw.println(" Get whether binding to print services provided by instant apps is " + + "allowed."); + } +} diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java index d4cbe7b1cf66e..4f0d6f1d55357 100644 --- a/services/print/java/com/android/server/print/RemotePrintService.java +++ b/services/print/java/com/android/server/print/RemotePrintService.java @@ -571,8 +571,8 @@ final class RemotePrintService implements DeathRecipient { mBinding = true; boolean wasBound = mContext.bindServiceAsUser(mIntent, mServiceConnection, - Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, - new UserHandle(mUserId)); + Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE + | Context.BIND_ALLOW_INSTANT, new UserHandle(mUserId)); if (!wasBound) { if (DEBUG) { diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java index 62185d782cbc1..4fbc14c0097f2 100644 --- a/services/print/java/com/android/server/print/UserState.java +++ b/services/print/java/com/android/server/print/UserState.java @@ -19,6 +19,7 @@ package com.android.server.print; import static android.content.pm.PackageManager.GET_META_DATA; import static android.content.pm.PackageManager.GET_SERVICES; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static android.content.pm.PackageManager.MATCH_INSTANT; import static com.android.internal.print.DumpUtils.writePrintJobInfo; import static com.android.internal.print.DumpUtils.writePrinterId; @@ -155,6 +156,11 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, */ private RemotePrintServiceRecommendationService mPrintServiceRecommendationsService; + /** + * Can services from instant apps be bound? (usually disabled, only used by testing) + */ + private boolean mIsInstantServiceAllowed; + public UserState(Context context, int userId, Object lock, boolean lowPriority) { mContext = context; mUserId = userId; @@ -872,9 +878,14 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, private void readInstalledPrintServicesLocked() { Set tempPrintServices = new HashSet(); + int queryIntentFlags = GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING; + + if (mIsInstantServiceAllowed) { + queryIntentFlags |= MATCH_INSTANT; + } + List installedServices = mContext.getPackageManager() - .queryIntentServicesAsUser(mQueryIntent, - GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING, mUserId); + .queryIntentServicesAsUser(mQueryIntent, queryIntentFlags, mUserId); final int installedCount = installedServices.size(); for (int i = 0, count = installedCount; i < count; i++) { @@ -1185,6 +1196,18 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, } } + public boolean getBindInstantServiceAllowed() { + return mIsInstantServiceAllowed; + } + + public void setBindInstantServiceAllowed(boolean allowed) { + synchronized (mLock) { + mIsInstantServiceAllowed = allowed; + + updateIfNeededLocked(); + } + } + private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient { @NonNull final IPrintJobStateChangeListener listener; final int appId;