diff options
author | Philip P. Moltmann <moltmann@google.com> | 2018-05-10 15:22:12 -0700 |
---|---|---|
committer | Philip P. Moltmann <moltmann@google.com> | 2018-05-10 15:26:39 -0700 |
commit | b3baaab4af7e1ed8dfc5da1c976cc34d135fb82b (patch) | |
tree | 139ea335eeddff9cb8afb231d8c3e1a794fd12c9 /services/print | |
parent | a1aafd771827b7625b059842451cf63abbb4b41f (diff) |
Allow Print subsystem to work with services provided by instant app
Most functionality works, but the PrintActivity cannot directly interact
with the instant service.
As instant services should only appear in tests this functionality needs
to be enabled via shell commands.
Fixes: 79484768
Test: cts-tradefed run commandAndExit cts-instant-dev -m CtsPrintTestCases
cts-tradefed run commandAndExit cts-dev -m CtsPrintTestCases
Change-Id: Ie4663c72b8c0f959b5d172ef28875479d120e386
Diffstat (limited to 'services/print')
4 files changed, 194 insertions, 6 deletions
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 83a125d1fc36..dc55179bdc9e 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; @@ -122,6 +128,13 @@ public final class PrintManagerService extends SystemService { } @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) { adapter = Preconditions.checkNotNull(adapter); @@ -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<ResolveInfo> 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 000000000000..11642e5a45e9 --- /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 <USER_ID>] true|false "); + pw.println(" Set whether binding to print services provided by instant apps is " + + "allowed."); + pw.println(" get-bind-instant-service-allowed [--user <USER_ID>]"); + 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 d4cbe7b1cf66..4f0d6f1d5535 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 62185d782cbc..4fbc14c0097f 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<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>(); + int queryIntentFlags = GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING; + + if (mIsInstantServiceAllowed) { + queryIntentFlags |= MATCH_INSTANT; + } + List<ResolveInfo> 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; |