diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index a769590447ab5..65537adccbc6f 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -55,6 +55,7 @@ import android.util.SparseArray; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.intelligence.IntelligenceManagerInternal; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.WindowManagerInternal; @@ -157,6 +158,7 @@ public class ClipboardService extends SystemService { private final IUserManager mUm; private final PackageManager mPm; private final AppOpsManager mAppOps; + private final IntelligenceManagerInternal mIm; private final IBinder mPermissionOwner; private HostClipboardMonitor mHostClipboardMonitor = null; private Thread mHostMonitorThread = null; @@ -176,6 +178,7 @@ public class ClipboardService extends SystemService { mPm = getContext().getPackageManager(); mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); + mIm = LocalServices.getService(IntelligenceManagerInternal.class); final IBinder permOwner = mUgmInternal.newUriPermissionOwner("clipboard"); mPermissionOwner = permOwner; if (IS_EMULATOR) { @@ -635,8 +638,9 @@ public class ClipboardService extends SystemService { return true; } // The default IME is always allowed to access the clipboard. + int userId = UserHandle.getUserId(callingUid); String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, UserHandle.getUserId(callingUid)); + Settings.Secure.DEFAULT_INPUT_METHOD, userId); if (!TextUtils.isEmpty(defaultIme)) { final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName(); if (imePkg.equals(callingPackage)) { @@ -646,13 +650,18 @@ public class ClipboardService extends SystemService { switch (op) { case AppOpsManager.OP_READ_CLIPBOARD: - // Clipboard can only be read by applications with focus. - boolean uidFocused = mWm.isUidFocused(callingUid); - if (!uidFocused) { - Slog.e(TAG, "Denying clipboard access to " + callingPackage - + ", application is not in focus."); + // Clipboard can only be read by applications with focus.. + boolean allowed = mWm.isUidFocused(callingUid); + if (!allowed && mIm != null) { + // ...or the Intelligence Service + allowed = mIm.isIntelligenceServiceForUser(callingUid, userId); } - return uidFocused; + if (!allowed) { + Slog.e(TAG, "Denying clipboard access to " + callingPackage + + ", application is not in focus neither is the IntelligeService for " + + "user " + userId); + } + return allowed; case AppOpsManager.OP_WRITE_CLIPBOARD: // Writing is allowed without focus. return true; diff --git a/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java new file mode 100644 index 0000000000000..0ed56ff4ca137 --- /dev/null +++ b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java @@ -0,0 +1,33 @@ +/* + * 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.intelligence; + +import android.annotation.UserIdInt; + +/** + * Intelligence Manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class IntelligenceManagerInternal { + + /** + * Checks whether the given {@code uid} owns the + * {@link android.service.intelligence.IntelligenceService} implementation associated with the + * given {@code userId}. + */ + public abstract boolean isIntelligenceServiceForUser(int uid, @UserIdInt int userId); +} diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java index 43d4a4476c11d..57633005f041d 100644 --- a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java +++ b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java @@ -53,6 +53,8 @@ public final class IntelligenceManagerService @GuardedBy("mLock") private ActivityManagerInternal mAm; + private final LocalService mLocalService = new LocalService(); + public IntelligenceManagerService(Context context) { super(context, UserManager.DISALLOW_INTELLIGENCE_CAPTURE); } @@ -73,6 +75,7 @@ public final class IntelligenceManagerService public void onStart() { publishBinderService(INTELLIGENCE_MANAGER_SERVICE, new IntelligenceManagerServiceStub()); + publishLocalService(IntelligenceManagerInternal.class, mLocalService); } private ActivityManagerInternal getAmInternal() { @@ -139,4 +142,19 @@ public final class IntelligenceManagerService } } } + + private final class LocalService extends IntelligenceManagerInternal { + + @Override + public boolean isIntelligenceServiceForUser(int uid, int userId) { + synchronized (mLock) { + final IntelligencePerUserService service = peekServiceForUserLocked(userId); + if (service != null) { + return service.isIntelligenceServiceForUserLocked(uid); + } + } + + return false; + } + } } diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java index 584b872c64d0e..829d2f4b69632 100644 --- a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java +++ b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java @@ -158,6 +158,11 @@ final class IntelligencePerUserService mSessions.remove(sessionId); } + @GuardedBy("mLock") + public boolean isIntelligenceServiceForUserLocked(int uid) { + return uid == getServiceUidLocked(); + } + @Override protected void dumpLocked(String prefix, PrintWriter pw) { super.dumpLocked(prefix, pw); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 8aa6419db81a6..3bb8ce3afd74e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1136,6 +1136,13 @@ public final class SystemServer { traceEnd(); } + if (!disableIntelligence) { + traceBeginAndSlog("StartIntelligenceService"); + mSystemServiceManager.startService(INTELLIGENCE_MANAGER_SERVICE_CLASS); + traceEnd(); + } + + // NOTE: ClipboardService indirectly depends on IntelligenceService traceBeginAndSlog("StartClipboardService"); mSystemServiceManager.startService(ClipboardService.class); traceEnd(); @@ -1767,12 +1774,6 @@ public final class SystemServer { traceEnd(); } - if (!disableIntelligence) { - traceBeginAndSlog("StartIntelligenceService"); - mSystemServiceManager.startService(INTELLIGENCE_MANAGER_SERVICE_CLASS); - traceEnd(); - } - traceBeginAndSlog("AppServiceManager"); mSystemServiceManager.startService(AppBindingService.Lifecycle.class); traceEnd();