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