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