• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.slice;
18 
19 import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
20 import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
21 import static android.content.ContentProvider.getUriWithoutUserId;
22 import static android.content.ContentProvider.getUserIdFromUri;
23 import static android.content.ContentProvider.maybeAddUserId;
24 import static android.content.pm.PackageManager.PERMISSION_DENIED;
25 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
26 import static android.os.Process.SYSTEM_UID;
27 
28 import android.Manifest.permission;
29 import android.annotation.NonNull;
30 import android.app.AppOpsManager;
31 import android.app.role.OnRoleHoldersChangedListener;
32 import android.app.role.RoleManager;
33 import android.app.slice.ISliceManager;
34 import android.app.slice.SliceSpec;
35 import android.app.usage.UsageStatsManagerInternal;
36 import android.content.BroadcastReceiver;
37 import android.content.ComponentName;
38 import android.content.ContentProvider;
39 import android.content.ContentResolver;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.IntentFilter;
43 import android.content.pm.PackageManager;
44 import android.content.pm.PackageManagerInternal;
45 import android.content.pm.ProviderInfo;
46 import android.content.pm.ResolveInfo;
47 import android.net.Uri;
48 import android.os.Binder;
49 import android.os.Handler;
50 import android.os.IBinder;
51 import android.os.Looper;
52 import android.os.Process;
53 import android.os.RemoteException;
54 import android.os.ResultReceiver;
55 import android.os.ShellCallback;
56 import android.os.UserHandle;
57 import android.util.ArrayMap;
58 import android.util.Slog;
59 import android.util.SparseArray;
60 import android.util.Xml.Encoding;
61 
62 import com.android.internal.annotations.GuardedBy;
63 import com.android.internal.annotations.VisibleForTesting;
64 import com.android.internal.app.AssistUtils;
65 import com.android.server.LocalServices;
66 import com.android.server.ServiceThread;
67 import com.android.server.SystemService;
68 import com.android.server.SystemService.TargetUser;
69 
70 import org.xmlpull.v1.XmlPullParser;
71 import org.xmlpull.v1.XmlPullParserException;
72 import org.xmlpull.v1.XmlPullParserFactory;
73 import org.xmlpull.v1.XmlSerializer;
74 
75 import java.io.ByteArrayInputStream;
76 import java.io.ByteArrayOutputStream;
77 import java.io.FileDescriptor;
78 import java.io.IOException;
79 import java.util.ArrayList;
80 import java.util.List;
81 import java.util.Objects;
82 import java.util.concurrent.Executor;
83 import java.util.function.Supplier;
84 
85 public class SliceManagerService extends ISliceManager.Stub {
86 
87     private static final String TAG = "SliceManagerService";
88     private final Object mLock = new Object();
89 
90     private final Context mContext;
91     private final PackageManagerInternal mPackageManagerInternal;
92     private final AppOpsManager mAppOps;
93     private final AssistUtils mAssistUtils;
94 
95     @GuardedBy("mLock")
96     private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
97     @GuardedBy("mLock")
98     private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
99     @GuardedBy("mLock")
100     private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
101     private final Handler mHandler;
102 
103     private final SlicePermissionManager mPermissions;
104     private final UsageStatsManagerInternal mAppUsageStats;
105 
SliceManagerService(Context context)106     public SliceManagerService(Context context) {
107         this(context, createHandler().getLooper());
108     }
109 
110     @VisibleForTesting
SliceManagerService(Context context, Looper looper)111     SliceManagerService(Context context, Looper looper) {
112         mContext = context;
113         mPackageManagerInternal = Objects.requireNonNull(
114                 LocalServices.getService(PackageManagerInternal.class));
115         mAppOps = context.getSystemService(AppOpsManager.class);
116         mAssistUtils = new AssistUtils(context);
117         mHandler = new Handler(looper);
118 
119         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
120 
121         mPermissions = new SlicePermissionManager(mContext, looper);
122 
123         IntentFilter filter = new IntentFilter();
124         filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
125         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
126         filter.addDataScheme("package");
127         mRoleObserver = new RoleObserver();
128         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
129     }
130 
131     ///  ----- Lifecycle stuff -----
systemReady()132     private void systemReady() {
133     }
134 
onUnlockUser(int userId)135     private void onUnlockUser(int userId) {
136     }
137 
onStopUser(int userId)138     private void onStopUser(int userId) {
139         synchronized (mLock) {
140             mPinnedSlicesByUri.values().removeIf(s -> getUserIdFromUri(s.getUri()) == userId);
141         }
142     }
143 
144     ///  ----- ISliceManager stuff -----
145     @Override
getPinnedSlices(String pkg)146     public Uri[] getPinnedSlices(String pkg) {
147         verifyCaller(pkg);
148         int callingUser = Binder.getCallingUserHandle().getIdentifier();
149         ArrayList<Uri> ret = new ArrayList<>();
150         synchronized (mLock) {
151             for (PinnedSliceState state : mPinnedSlicesByUri.values()) {
152                 if (Objects.equals(pkg, state.getPkg())) {
153                     Uri uri = state.getUri();
154                     int userId = ContentProvider.getUserIdFromUri(uri, callingUser);
155                     if (userId == callingUser) {
156                         ret.add(ContentProvider.getUriWithoutUserId(uri));
157                     }
158                 }
159             }
160         }
161         return ret.toArray(new Uri[ret.size()]);
162     }
163 
164     @Override
pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token)165     public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token)
166             throws RemoteException {
167         verifyCaller(pkg);
168         enforceAccess(pkg, uri);
169         int user = Binder.getCallingUserHandle().getIdentifier();
170         uri = maybeAddUserId(uri, user);
171         String slicePkg = getProviderPkg(uri, user);
172         getOrCreatePinnedSlice(uri, slicePkg).pin(pkg, specs, token);
173 
174         mHandler.post(() -> {
175             if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
176                 mAppUsageStats.reportEvent(slicePkg, user,
177                         isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
178                                 ? SLICE_PINNED_PRIV : SLICE_PINNED);
179             }
180         });
181     }
182 
183     @Override
unpinSlice(String pkg, Uri uri, IBinder token)184     public void unpinSlice(String pkg, Uri uri, IBinder token) throws RemoteException {
185         verifyCaller(pkg);
186         enforceAccess(pkg, uri);
187         uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
188         try {
189             PinnedSliceState slice = getPinnedSlice(uri);
190             if (slice != null && slice.unpin(pkg, token)) {
191                 removePinnedSlice(uri);
192             }
193         } catch (IllegalStateException exception) {
194             Slog.w(TAG, exception.getMessage());
195         }
196     }
197 
198     @Override
hasSliceAccess(String pkg)199     public boolean hasSliceAccess(String pkg) throws RemoteException {
200         verifyCaller(pkg);
201         return hasFullSliceAccess(pkg, Binder.getCallingUserHandle().getIdentifier());
202     }
203 
204     @Override
getPinnedSpecs(Uri uri, String pkg)205     public SliceSpec[] getPinnedSpecs(Uri uri, String pkg) throws RemoteException {
206         verifyCaller(pkg);
207         enforceAccess(pkg, uri);
208         uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
209         return getPinnedSlice(uri).getSpecs();
210     }
211 
212     @Override
grantSlicePermission(String pkg, String toPkg, Uri uri)213     public void grantSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
214         verifyCaller(pkg);
215         int user = Binder.getCallingUserHandle().getIdentifier();
216         enforceOwner(pkg, uri, user);
217         mPermissions.grantSliceAccess(toPkg, user, pkg, user, uri);
218     }
219 
220     @Override
revokeSlicePermission(String pkg, String toPkg, Uri uri)221     public void revokeSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
222         verifyCaller(pkg);
223         int user = Binder.getCallingUserHandle().getIdentifier();
224         enforceOwner(pkg, uri, user);
225         mPermissions.revokeSliceAccess(toPkg, user, pkg, user, uri);
226     }
227 
228     @Override
checkSlicePermission(Uri uri, String callingPkg, String pkg, int pid, int uid, String[] autoGrantPermissions)229     public int checkSlicePermission(Uri uri, String callingPkg, String pkg, int pid, int uid,
230             String[] autoGrantPermissions) {
231         int userId = UserHandle.getUserId(uid);
232         if (pkg == null) {
233             for (String p : mContext.getPackageManager().getPackagesForUid(uid)) {
234                 if (checkSlicePermission(uri, callingPkg, p, pid, uid, autoGrantPermissions)
235                         == PERMISSION_GRANTED) {
236                     return PERMISSION_GRANTED;
237                 }
238             }
239             return PERMISSION_DENIED;
240         }
241         if (hasFullSliceAccess(pkg, userId)) {
242             return PackageManager.PERMISSION_GRANTED;
243         }
244         if (mPermissions.hasPermission(pkg, userId, uri)) {
245             return PackageManager.PERMISSION_GRANTED;
246         }
247         if (autoGrantPermissions != null && callingPkg != null) {
248             // Need to own the Uri to call in with permissions to grant.
249             enforceOwner(callingPkg, uri, userId);
250             // b/208232850: Needs to verify caller before granting slice access
251             verifyCaller(callingPkg);
252             for (String perm : autoGrantPermissions) {
253                 if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
254                     int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
255                     String providerPkg = getProviderPkg(uri, providerUser);
256                     mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, uri);
257                     return PackageManager.PERMISSION_GRANTED;
258                 }
259             }
260         }
261         return PackageManager.PERMISSION_DENIED;
262     }
263 
264     @Override
grantPermissionFromUser(Uri uri, String pkg, String callingPkg, boolean allSlices)265     public void grantPermissionFromUser(Uri uri, String pkg, String callingPkg, boolean allSlices) {
266         verifyCaller(callingPkg);
267         getContext().enforceCallingOrSelfPermission(permission.MANAGE_SLICE_PERMISSIONS,
268                 "Slice granting requires MANAGE_SLICE_PERMISSIONS");
269         int userId = Binder.getCallingUserHandle().getIdentifier();
270         if (allSlices) {
271             mPermissions.grantFullAccess(pkg, userId);
272         } else {
273             // When granting, grant to all slices in the provider.
274             Uri grantUri = uri.buildUpon()
275                     .path("")
276                     .build();
277             int providerUser = ContentProvider.getUserIdFromUri(grantUri, userId);
278             String providerPkg = getProviderPkg(grantUri, providerUser);
279             mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, grantUri);
280         }
281         final long ident = Binder.clearCallingIdentity();
282         try {
283             mContext.getContentResolver().notifyChange(uri, null);
284         } finally {
285             Binder.restoreCallingIdentity(ident);
286         }
287     }
288 
289     // Backup/restore interface
290     @Override
getBackupPayload(int user)291     public byte[] getBackupPayload(int user) {
292         if (Binder.getCallingUid() != SYSTEM_UID) {
293             throw new SecurityException("Caller must be system");
294         }
295         //TODO: http://b/22388012
296         if (user != UserHandle.USER_SYSTEM) {
297             Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
298             return null;
299         }
300         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
301         try {
302             XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
303             out.setOutput(baos, Encoding.UTF_8.name());
304 
305             mPermissions.writeBackup(out);
306 
307             out.flush();
308             return baos.toByteArray();
309         } catch (IOException | XmlPullParserException e) {
310             Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
311         }
312         return null;
313     }
314 
315     @Override
applyRestore(byte[] payload, int user)316     public void applyRestore(byte[] payload, int user) {
317         if (Binder.getCallingUid() != SYSTEM_UID) {
318             throw new SecurityException("Caller must be system");
319         }
320         if (payload == null) {
321             Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
322             return;
323         }
324         //TODO: http://b/22388012
325         if (user != UserHandle.USER_SYSTEM) {
326             Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
327             return;
328         }
329         final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
330         try {
331             XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
332             parser.setInput(bais, Encoding.UTF_8.name());
333             mPermissions.readRestore(parser);
334         } catch (NumberFormatException | XmlPullParserException | IOException e) {
335             Slog.w(TAG, "applyRestore: error reading payload", e);
336         }
337     }
338 
339     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)340     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
341             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
342         new SliceShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
343     }
344 
345     ///  ----- internal code -----
enforceOwner(String pkg, Uri uri, int user)346     private void enforceOwner(String pkg, Uri uri, int user) {
347         if (!Objects.equals(getProviderPkg(uri, user), pkg) || pkg == null) {
348             throw new SecurityException("Caller must own " + uri);
349         }
350     }
351 
removePinnedSlice(Uri uri)352     protected void removePinnedSlice(Uri uri) {
353         synchronized (mLock) {
354             mPinnedSlicesByUri.remove(uri).destroy();
355         }
356     }
357 
getPinnedSlice(Uri uri)358     private PinnedSliceState getPinnedSlice(Uri uri) {
359         synchronized (mLock) {
360             PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
361             if (manager == null) {
362                 throw new IllegalStateException(String.format("Slice %s not pinned",
363                         uri.toString()));
364             }
365             return manager;
366         }
367     }
368 
getOrCreatePinnedSlice(Uri uri, String pkg)369     private PinnedSliceState getOrCreatePinnedSlice(Uri uri, String pkg) {
370         synchronized (mLock) {
371             PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
372             if (manager == null) {
373                 manager = createPinnedSlice(uri, pkg);
374                 mPinnedSlicesByUri.put(uri, manager);
375             }
376             return manager;
377         }
378     }
379 
380     @VisibleForTesting
createPinnedSlice(Uri uri, String pkg)381     protected PinnedSliceState createPinnedSlice(Uri uri, String pkg) {
382         return new PinnedSliceState(this, uri, pkg);
383     }
384 
getLock()385     public Object getLock() {
386         return mLock;
387     }
388 
getContext()389     public Context getContext() {
390         return mContext;
391     }
392 
getHandler()393     public Handler getHandler() {
394         return mHandler;
395     }
396 
checkAccess(String pkg, Uri uri, int uid, int pid)397     protected int checkAccess(String pkg, Uri uri, int uid, int pid) {
398         return checkSlicePermission(uri, null, pkg, pid, uid, null);
399     }
400 
getProviderPkg(Uri uri, int user)401     private String getProviderPkg(Uri uri, int user) {
402         final long ident = Binder.clearCallingIdentity();
403         try {
404             String providerName = getUriWithoutUserId(uri).getAuthority();
405             ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser(
406                     providerName, 0, getUserIdFromUri(uri, user));
407             return provider.packageName;
408         } finally {
409             Binder.restoreCallingIdentity(ident);
410         }
411     }
412 
enforceCrossUser(String pkg, Uri uri)413     private void enforceCrossUser(String pkg, Uri uri) {
414         int user = Binder.getCallingUserHandle().getIdentifier();
415         if (getUserIdFromUri(uri, user) != user) {
416             getContext().enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL,
417                     "Slice interaction across users requires INTERACT_ACROSS_USERS_FULL");
418         }
419     }
420 
enforceAccess(String pkg, Uri uri)421     private void enforceAccess(String pkg, Uri uri) throws RemoteException {
422         if (checkAccess(pkg, uri, Binder.getCallingUid(), Binder.getCallingPid())
423                 != PERMISSION_GRANTED) {
424             int userId = ContentProvider.getUserIdFromUri(uri,
425                     Binder.getCallingUserHandle().getIdentifier());
426             if (!Objects.equals(pkg, getProviderPkg(uri, userId))) {
427                 throw new SecurityException("Access to slice " + uri + " is required");
428             }
429         }
430         enforceCrossUser(pkg, uri);
431     }
432 
verifyCaller(String pkg)433     private void verifyCaller(String pkg) {
434         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
435     }
436 
hasFullSliceAccess(String pkg, int userId)437     private boolean hasFullSliceAccess(String pkg, int userId) {
438         final long ident = Binder.clearCallingIdentity();
439         try {
440             boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
441                     || isGrantedFullAccess(pkg, userId);
442             return ret;
443         } finally {
444             Binder.restoreCallingIdentity(ident);
445         }
446     }
447 
isAssistant(String pkg, int userId)448     private boolean isAssistant(String pkg, int userId) {
449         return getAssistantMatcher(userId).matches(pkg);
450     }
451 
isDefaultHomeApp(String pkg, int userId)452     private boolean isDefaultHomeApp(String pkg, int userId) {
453         return getHomeMatcher(userId).matches(pkg);
454     }
455 
getAssistantMatcher(int userId)456     private PackageMatchingCache getAssistantMatcher(int userId) {
457         PackageMatchingCache matcher = mAssistantLookup.get(userId);
458         if (matcher == null) {
459             matcher = new PackageMatchingCache(() -> getAssistant(userId));
460             mAssistantLookup.put(userId, matcher);
461         }
462         return matcher;
463     }
464 
getHomeMatcher(int userId)465     private PackageMatchingCache getHomeMatcher(int userId) {
466         PackageMatchingCache matcher = mHomeLookup.get(userId);
467         if (matcher == null) {
468             matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
469             mHomeLookup.put(userId, matcher);
470         }
471         return matcher;
472     }
473 
getAssistant(int userId)474     private String getAssistant(int userId) {
475         final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
476         if (cn == null) {
477             return null;
478         }
479         return cn.getPackageName();
480     }
481 
482     /**
483      * A cached value of the default home app
484      */
485     private String mCachedDefaultHome = null;
486 
487     // Based on getDefaultHome in ShortcutService.
488     // TODO: Unify if possible
489     @VisibleForTesting
getDefaultHome(int userId)490     protected String getDefaultHome(int userId) {
491 
492         // Set VERIFY to true to run the cache in "shadow" mode for cache
493         // testing.  Do not commit set to true;
494         final boolean VERIFY = false;
495 
496         if (mCachedDefaultHome != null) {
497             if (!VERIFY) {
498                 return mCachedDefaultHome;
499             }
500         }
501 
502         final long token = Binder.clearCallingIdentity();
503         try {
504             final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
505 
506             // Default launcher from package manager.
507             final ComponentName defaultLauncher = mPackageManagerInternal
508                     .getHomeActivitiesAsUser(allHomeCandidates, userId);
509 
510             ComponentName detected = defaultLauncher;
511 
512             // Cache the default launcher.  It is not a problem if the
513             // launcher is null - eventually, the default launcher will be
514             // set to something non-null.
515             mCachedDefaultHome = ((detected != null) ? detected.getPackageName() : null);
516 
517             if (detected == null) {
518                 // If we reach here, that means it's the first check since the user was created,
519                 // and there's already multiple launchers and there's no default set.
520                 // Find the system one with the highest priority.
521                 // (We need to check the priority too because of FallbackHome in Settings.)
522                 // If there's no system launcher yet, then no one can access slices, until
523                 // the user explicitly sets one.
524                 final int size = allHomeCandidates.size();
525 
526                 int lastPriority = Integer.MIN_VALUE;
527                 for (int i = 0; i < size; i++) {
528                     final ResolveInfo ri = allHomeCandidates.get(i);
529                     if (!ri.activityInfo.applicationInfo.isSystemApp()) {
530                         continue;
531                     }
532                     if (ri.priority < lastPriority) {
533                         continue;
534                     }
535                     detected = ri.activityInfo.getComponentName();
536                     lastPriority = ri.priority;
537                 }
538             }
539             final String ret = ((detected != null) ? detected.getPackageName() : null);
540             if (VERIFY) {
541                 if (mCachedDefaultHome != null && !mCachedDefaultHome.equals(ret)) {
542                     Slog.e(TAG, "getDefaultHome() cache failure, is " +
543                            mCachedDefaultHome + " should be " + ret);
544                 }
545             }
546             return ret;
547         } finally {
548             Binder.restoreCallingIdentity(token);
549         }
550     }
551 
invalidateCachedDefaultHome()552     public void invalidateCachedDefaultHome() {
553         mCachedDefaultHome = null;
554     }
555 
556     /**
557      * Listen for changes in the roles, and invalidate the cached default
558      * home as necessary.
559      */
560     private RoleObserver mRoleObserver;
561 
562     class RoleObserver implements OnRoleHoldersChangedListener {
563         private RoleManager mRm;
564         private final Executor mExecutor;
565 
RoleObserver()566         RoleObserver() {
567             mExecutor = mContext.getMainExecutor();
568             register();
569         }
570 
register()571         public void register() {
572             mRm = mContext.getSystemService(RoleManager.class);
573             if (mRm != null) {
574                 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
575                 invalidateCachedDefaultHome();
576             }
577         }
578 
579         @Override
onRoleHoldersChanged(@onNull String roleName, @NonNull UserHandle user)580         public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
581             if (RoleManager.ROLE_HOME.equals(roleName)) {
582                 invalidateCachedDefaultHome();
583             }
584         }
585     }
586 
isGrantedFullAccess(String pkg, int userId)587     private boolean isGrantedFullAccess(String pkg, int userId) {
588         return mPermissions.hasFullAccess(pkg, userId);
589     }
590 
createHandler()591     private static ServiceThread createHandler() {
592         ServiceThread handlerThread = new ServiceThread(TAG,
593                 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
594         handlerThread.start();
595         return handlerThread;
596     }
597 
598     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
599         @Override
600         public void onReceive(Context context, Intent intent) {
601             final int userId  = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
602             if (userId == UserHandle.USER_NULL) {
603                 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
604                 return;
605             }
606             Uri data = intent.getData();
607             String pkg = data != null ? data.getSchemeSpecificPart() : null;
608             if (pkg == null) {
609                 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
610                 return;
611             }
612             switch (intent.getAction()) {
613                 case Intent.ACTION_PACKAGE_REMOVED:
614                     final boolean replacing =
615                             intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
616                     if (!replacing) {
617                         mPermissions.removePkg(pkg, userId);
618                     }
619                     break;
620                 case Intent.ACTION_PACKAGE_DATA_CLEARED:
621                     mPermissions.removePkg(pkg, userId);
622                     break;
623             }
624         }
625     };
626 
getAllPackagesGranted(String authority)627     public String[] getAllPackagesGranted(String authority) {
628         String pkg = getProviderPkg(new Uri.Builder()
629                 .scheme(ContentResolver.SCHEME_CONTENT)
630                 .authority(authority)
631                 .build(), 0);
632         return mPermissions.getAllPackagesGranted(pkg);
633     }
634 
635     /**
636      * Holder that caches a package that has access to a slice.
637      */
638     static class PackageMatchingCache {
639 
640         private final Supplier<String> mPkgSource;
641         private String mCurrentPkg;
642 
PackageMatchingCache(Supplier<String> pkgSource)643         public PackageMatchingCache(Supplier<String> pkgSource) {
644             mPkgSource = pkgSource;
645         }
646 
matches(String pkgCandidate)647         public boolean matches(String pkgCandidate) {
648             if (pkgCandidate == null) return false;
649 
650             if (Objects.equals(pkgCandidate, mCurrentPkg)) {
651                 return true;
652             }
653             // Failed on cached value, try updating.
654             mCurrentPkg = mPkgSource.get();
655             return Objects.equals(pkgCandidate, mCurrentPkg);
656         }
657     }
658 
659     public static class Lifecycle extends SystemService {
660         private SliceManagerService mService;
661 
Lifecycle(Context context)662         public Lifecycle(Context context) {
663             super(context);
664         }
665 
666         @Override
onStart()667         public void onStart() {
668             mService = new SliceManagerService(getContext());
669             publishBinderService(Context.SLICE_SERVICE, mService);
670         }
671 
672         @Override
onBootPhase(int phase)673         public void onBootPhase(int phase) {
674             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
675                 mService.systemReady();
676             }
677         }
678 
679         @Override
onUserUnlocking(@onNull TargetUser user)680         public void onUserUnlocking(@NonNull TargetUser user) {
681             mService.onUnlockUser(user.getUserIdentifier());
682         }
683 
684         @Override
onUserStopping(@onNull TargetUser user)685         public void onUserStopping(@NonNull TargetUser user) {
686             mService.onStopUser(user.getUserIdentifier());
687         }
688     }
689 
690     private class SliceGrant {
691         private final Uri mUri;
692         private final String mPkg;
693         private final int mUserId;
694 
SliceGrant(Uri uri, String pkg, int userId)695         public SliceGrant(Uri uri, String pkg, int userId) {
696             mUri = uri;
697             mPkg = pkg;
698             mUserId = userId;
699         }
700 
701         @Override
hashCode()702         public int hashCode() {
703             return mUri.hashCode() + mPkg.hashCode();
704         }
705 
706         @Override
equals(Object obj)707         public boolean equals(Object obj) {
708             if (!(obj instanceof SliceGrant)) return false;
709             SliceGrant other = (SliceGrant) obj;
710             return Objects.equals(other.mUri, mUri) && Objects.equals(other.mPkg, mPkg)
711                     && (other.mUserId == mUserId);
712         }
713     }
714 }
715