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