1 /* 2 * Copyright (C) 2016 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 package com.android.server.pm; 17 18 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyOrNull; 19 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyStringOrNull; 20 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.cloneShortcutList; 21 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet; 22 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; 23 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle; 24 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set; 25 26 import static org.mockito.ArgumentMatchers.anyBoolean; 27 import static org.mockito.Matchers.any; 28 import static org.mockito.Matchers.anyInt; 29 import static org.mockito.Matchers.anyString; 30 import static org.mockito.Matchers.eq; 31 import static org.mockito.Mockito.doAnswer; 32 import static org.mockito.Mockito.mock; 33 import static org.mockito.Mockito.reset; 34 import static org.mockito.Mockito.spy; 35 import static org.mockito.Mockito.times; 36 import static org.mockito.Mockito.verify; 37 import static org.mockito.Mockito.when; 38 39 import android.annotation.NonNull; 40 import android.annotation.UserIdInt; 41 import android.app.Activity; 42 import android.app.ActivityManager; 43 import android.app.ActivityManagerInternal; 44 import android.app.IUidObserver; 45 import android.app.usage.UsageStatsManagerInternal; 46 import android.content.ActivityNotFoundException; 47 import android.content.BroadcastReceiver; 48 import android.content.ComponentName; 49 import android.content.Context; 50 import android.content.Intent; 51 import android.content.IntentFilter; 52 import android.content.IntentSender; 53 import android.content.pm.ActivityInfo; 54 import android.content.pm.ApplicationInfo; 55 import android.content.pm.ILauncherApps; 56 import android.content.pm.LauncherApps; 57 import android.content.pm.LauncherApps.ShortcutQuery; 58 import android.content.pm.PackageInfo; 59 import android.content.pm.PackageManager; 60 import android.content.pm.PackageManagerInternal; 61 import android.content.pm.PackageParser; 62 import android.content.pm.ResolveInfo; 63 import android.content.pm.ShortcutInfo; 64 import android.content.pm.ShortcutManager; 65 import android.content.pm.ShortcutServiceInternal; 66 import android.content.pm.Signature; 67 import android.content.pm.SigningInfo; 68 import android.content.pm.UserInfo; 69 import android.content.res.Resources; 70 import android.content.res.XmlResourceParser; 71 import android.graphics.drawable.Icon; 72 import android.net.Uri; 73 import android.os.Bundle; 74 import android.os.FileUtils; 75 import android.os.Handler; 76 import android.os.Looper; 77 import android.os.PersistableBundle; 78 import android.os.Process; 79 import android.os.RemoteException; 80 import android.os.UserHandle; 81 import android.os.UserManager; 82 import android.os.UserManagerInternal; 83 import android.test.InstrumentationTestCase; 84 import android.test.mock.MockContext; 85 import android.util.ArrayMap; 86 import android.util.Log; 87 import android.util.Pair; 88 89 import com.android.internal.util.Preconditions; 90 import com.android.server.LocalServices; 91 import com.android.server.SystemService; 92 import com.android.server.pm.LauncherAppsService.LauncherAppsImpl; 93 import com.android.server.pm.ShortcutUser.PackageWithUser; 94 95 import org.junit.Assert; 96 import org.mockito.ArgumentCaptor; 97 import org.mockito.invocation.InvocationOnMock; 98 import org.mockito.stubbing.Answer; 99 100 import java.io.BufferedReader; 101 import java.io.ByteArrayOutputStream; 102 import java.io.File; 103 import java.io.FileReader; 104 import java.io.IOException; 105 import java.io.InputStreamReader; 106 import java.io.PrintWriter; 107 import java.security.cert.CertificateEncodingException; 108 import java.security.cert.CertificateException; 109 import java.util.ArrayList; 110 import java.util.HashMap; 111 import java.util.HashSet; 112 import java.util.LinkedHashMap; 113 import java.util.List; 114 import java.util.Locale; 115 import java.util.Map; 116 import java.util.Set; 117 import java.util.function.BiFunction; 118 import java.util.function.BiPredicate; 119 import java.util.function.Consumer; 120 import java.util.function.Function; 121 122 public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { 123 protected static final String TAG = "ShortcutManagerTest"; 124 125 protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true 126 127 /** 128 * Whether to enable dump or not. Should be only true when debugging to avoid bugs where 129 * dump affecting the behavior. 130 */ 131 protected static final boolean ENABLE_DUMP = false // DO NOT SUBMIT WITH true 132 || DUMP_IN_TEARDOWN || ShortcutService.DEBUG; 133 134 protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability. 135 136 protected static final String MAIN_ACTIVITY_CLASS = "MainActivity"; 137 protected static final String PIN_CONFIRM_ACTIVITY_CLASS = "PinConfirmActivity"; 138 139 // public for mockito 140 public class BaseContext extends MockContext { 141 @Override 142 public Object getSystemService(String name) { 143 switch (name) { 144 case Context.USER_SERVICE: 145 return mMockUserManager; 146 } 147 throw new UnsupportedOperationException(); 148 } 149 150 @Override 151 public String getSystemServiceName(Class<?> serviceClass) { 152 return getTestContext().getSystemServiceName(serviceClass); 153 } 154 155 @Override 156 public PackageManager getPackageManager() { 157 return mMockPackageManager; 158 } 159 160 @Override 161 public Resources getResources() { 162 return getTestContext().getResources(); 163 } 164 165 @Override 166 public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, 167 IntentFilter filter, String broadcastPermission, Handler scheduler) { 168 // ignore. 169 return null; 170 } 171 172 @Override 173 public void unregisterReceiver(BroadcastReceiver receiver) { 174 // ignore. 175 } 176 177 @Override 178 public void startActivityAsUser(Intent intent, UserHandle user) { 179 // ignore, use spy to intercept it. 180 } 181 } 182 183 /** Context used in the client side */ 184 public class ClientContext extends BaseContext { 185 @Override 186 public String getPackageName() { 187 return mInjectedClientPackage; 188 } 189 190 @Override 191 public int getUserId() { 192 return getCallingUserId(); 193 } 194 } 195 196 /** Context used in the service side */ 197 public class ServiceContext extends BaseContext { 198 long injectClearCallingIdentity() { 199 final int prevCallingUid = mInjectedCallingUid; 200 mInjectedCallingUid = Process.SYSTEM_UID; 201 return prevCallingUid; 202 } 203 204 void injectRestoreCallingIdentity(long token) { 205 mInjectedCallingUid = (int) token; 206 } 207 208 @Override 209 public int getUserId() { 210 return UserHandle.USER_SYSTEM; 211 } 212 213 public PackageInfo injectGetActivitiesWithMetadata( 214 String packageName, @UserIdInt int userId) { 215 return BaseShortcutManagerTest.this.injectGetActivitiesWithMetadata(packageName, userId); 216 } 217 218 public XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) { 219 return BaseShortcutManagerTest.this.injectXmlMetaData(activityInfo, key); 220 } 221 222 public void sendIntentSender(IntentSender intent) { 223 // Placeholder for spying. 224 } 225 } 226 227 /** ShortcutService with injection override methods. */ 228 protected final class ShortcutServiceTestable extends ShortcutService { 229 final ServiceContext mContext; 230 IUidObserver mUidObserver; 231 232 public ShortcutServiceTestable(ServiceContext context, Looper looper) { 233 super(context, looper, /* onyForPackageManagerApis */ false); 234 mContext = context; 235 } 236 237 @Override 238 public String injectGetLocaleTagsForUser(@UserIdInt int userId) { 239 return mInjectedLocale.toLanguageTag(); 240 } 241 242 @Override 243 boolean injectShouldPerformVerification() { 244 return true; // Always verify during unit tests. 245 } 246 247 @Override 248 String injectShortcutManagerConstants() { 249 return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + "," 250 + ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + "," 251 + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=" 252 + MAX_UPDATES_PER_INTERVAL + "," 253 + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + "," 254 + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=" 255 + MAX_ICON_DIMENSION_LOWRAM + "," 256 + ConfigConstants.KEY_ICON_FORMAT + "=PNG," 257 + ConfigConstants.KEY_ICON_QUALITY + "=100"; 258 } 259 260 @Override 261 long injectClearCallingIdentity() { 262 return mContext.injectClearCallingIdentity(); 263 } 264 265 @Override 266 void injectRestoreCallingIdentity(long token) { 267 mContext.injectRestoreCallingIdentity(token); 268 } 269 270 @Override 271 int injectDipToPixel(int dip) { 272 return dip; 273 } 274 275 @Override 276 long injectCurrentTimeMillis() { 277 return mInjectedCurrentTimeMillis; 278 } 279 280 @Override 281 long injectElapsedRealtime() { 282 // TODO This should be kept separately from mInjectedCurrentTimeMillis, since 283 // this should increase even if we rewind mInjectedCurrentTimeMillis in some tests. 284 return mInjectedCurrentTimeMillis - START_TIME; 285 } 286 287 @Override 288 long injectUptimeMillis() { 289 return mInjectedCurrentTimeMillis - START_TIME - mDeepSleepTime; 290 } 291 292 @Override 293 int injectBinderCallingUid() { 294 return mInjectedCallingUid; 295 } 296 297 @Override 298 int injectBinderCallingPid() { 299 // Note it's not used in tests, so just return a "random" value. 300 return mInjectedCallingUid * 123; 301 } 302 303 @Override 304 int injectGetPackageUid(String packageName, int userId) { 305 return getInjectedPackageInfo(packageName, userId, false).applicationInfo.uid; 306 } 307 308 @Override 309 File injectSystemDataPath() { 310 return new File(mInjectedFilePathRoot, "system"); 311 } 312 313 @Override 314 File injectUserDataPath(@UserIdInt int userId) { 315 return new File(mInjectedFilePathRoot, "user-" + userId); 316 } 317 318 @Override 319 void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) { 320 // Can't check 321 } 322 323 @Override 324 boolean injectIsLowRamDevice() { 325 return mInjectedIsLowRamDevice; 326 } 327 328 @Override 329 void injectRegisterUidObserver(IUidObserver observer, int which) { 330 mUidObserver = observer; 331 } 332 333 @Override 334 boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId, 335 int callingPid, int callingUid) { 336 return mDefaultLauncherChecker.test(callingPackage, userId); 337 } 338 339 @Override 340 boolean injectHasUnlimitedShortcutsApiCallsPermission(int callingPid, int callingUid) { 341 return mInjectHasUnlimitedShortcutsApiCallsPermission; 342 } 343 344 @Override 345 ComponentName getDefaultLauncher(@UserIdInt int userId) { 346 final ComponentName activity = mDefaultLauncher.get(userId); 347 if (activity != null) { 348 return activity; 349 } 350 return super.getDefaultLauncher(userId); 351 } 352 353 @Override 354 PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId, 355 boolean getSignatures) { 356 return getInjectedPackageInfo(packageName, userId, getSignatures); 357 } 358 359 @Override 360 ApplicationInfo injectApplicationInfoWithUninstalled( 361 String packageName, @UserIdInt int userId) { 362 PackageInfo pi = injectPackageInfoWithUninstalled( 363 packageName, userId, /* getSignatures= */ false); 364 return pi != null ? pi.applicationInfo : null; 365 } 366 367 @Override 368 List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId) { 369 return BaseShortcutManagerTest.this.getInstalledPackagesWithUninstalled(userId); 370 } 371 372 @Override 373 ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(ComponentName activity, 374 @UserIdInt int userId) { 375 final PackageInfo pi = mContext.injectGetActivitiesWithMetadata( 376 activity.getPackageName(), userId); 377 if (pi == null || pi.activities == null) { 378 return null; 379 } 380 for (ActivityInfo ai : pi.activities) { 381 if (!mEnabledActivityChecker.test(ai.getComponentName(), userId)) { 382 continue; 383 } 384 if (activity.equals(ai.getComponentName())) { 385 return ai; 386 } 387 } 388 return null; 389 } 390 391 @Override 392 boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) { 393 if (!mEnabledActivityChecker.test(activity, userId)) { 394 return false; 395 } 396 return mMainActivityChecker.test(activity, userId); 397 } 398 399 @Override 400 List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) { 401 final PackageInfo pi = mContext.injectGetActivitiesWithMetadata( 402 packageName, userId); 403 if (pi == null || pi.activities == null) { 404 return null; 405 } 406 final ArrayList<ResolveInfo> ret = new ArrayList<>(pi.activities.length); 407 for (int i = 0; i < pi.activities.length; i++) { 408 if (!mEnabledActivityChecker.test(pi.activities[i].getComponentName(), userId)) { 409 continue; 410 } 411 final ResolveInfo ri = new ResolveInfo(); 412 ri.activityInfo = pi.activities[i]; 413 ret.add(ri); 414 } 415 416 return ret; 417 } 418 419 @Override 420 ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) { 421 return mMainActivityFetcher.apply(packageName, userId); 422 } 423 424 @Override 425 ComponentName injectGetPinConfirmationActivity(@NonNull String launcherPackageName, 426 int launcherUserId, int requestType) { 427 return mPinConfirmActivityFetcher.apply(launcherPackageName, launcherUserId); 428 } 429 430 @Override 431 boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) { 432 return mEnabledActivityChecker.test(activity, userId); 433 } 434 435 @Override 436 XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) { 437 return mContext.injectXmlMetaData(activityInfo, key); 438 } 439 440 @Override 441 void injectPostToHandler(Runnable r) { 442 runOnHandler(r); 443 } 444 445 @Override 446 void injectRunOnNewThread(Runnable r) { 447 runOnHandler(r); 448 } 449 450 @Override 451 void injectEnforceCallingPermission(String permission, String message) { 452 if (!mCallerPermissions.contains(permission)) { 453 throw new SecurityException("Missing permission: " + permission); 454 } 455 } 456 457 @Override 458 boolean injectIsSafeModeEnabled() { 459 return mSafeMode; 460 } 461 462 @Override 463 String injectBuildFingerprint() { 464 return mInjectedBuildFingerprint; 465 } 466 467 @Override 468 void injectSendIntentSender(IntentSender intent, Intent extras) { 469 mContext.sendIntentSender(intent); 470 } 471 472 @Override 473 boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) { 474 return mInjectCheckAccessShortcutsPermission; 475 } 476 477 @Override 478 void wtf(String message, Throwable th) { 479 // During tests, WTF is fatal. 480 fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th)); 481 } 482 } 483 484 /** ShortcutManager with injection override methods. */ 485 protected class ShortcutManagerTestable extends ShortcutManager { 486 public ShortcutManagerTestable(Context context, ShortcutServiceTestable service) { 487 super(context, service); 488 } 489 490 @Override 491 protected int injectMyUserId() { 492 return UserHandle.getUserId(mInjectedCallingUid); 493 } 494 495 @Override 496 public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 497 // Note to simulate the binder RPC, we need to clone the incoming arguments. 498 // Otherwise bad things will happen because they're mutable. 499 return super.setDynamicShortcuts(cloneShortcutList(shortcutInfoList)); 500 } 501 502 @Override 503 public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 504 // Note to simulate the binder RPC, we need to clone the incoming arguments. 505 return super.addDynamicShortcuts(cloneShortcutList(shortcutInfoList)); 506 } 507 508 @Override 509 public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) { 510 // Note to simulate the binder RPC, we need to clone the incoming arguments. 511 return super.updateShortcuts(cloneShortcutList(shortcutInfoList)); 512 } 513 } 514 515 protected class LauncherAppImplTestable extends LauncherAppsImpl { 516 final ServiceContext mContext; 517 518 public LauncherAppImplTestable(ServiceContext context) { 519 super(context); 520 mContext = context; 521 } 522 523 @Override 524 public void verifyCallingPackage(String callingPackage) { 525 // SKIP 526 } 527 528 @Override 529 void postToPackageMonitorHandler(Runnable r) { 530 runOnHandler(r); 531 } 532 533 @Override 534 int injectBinderCallingUid() { 535 return mInjectedCallingUid; 536 } 537 538 @Override 539 int injectBinderCallingPid() { 540 // Note it's not used in tests, so just return a "random" value. 541 return mInjectedCallingUid * 123; 542 } 543 544 @Override 545 long injectClearCallingIdentity() { 546 final int prevCallingUid = mInjectedCallingUid; 547 mInjectedCallingUid = Process.SYSTEM_UID; 548 return prevCallingUid; 549 } 550 551 @Override 552 void injectRestoreCallingIdentity(long token) { 553 mInjectedCallingUid = (int) token; 554 } 555 } 556 557 protected class LauncherAppsTestable extends LauncherApps { 558 public LauncherAppsTestable(Context context, ILauncherApps service) { 559 super(context, service); 560 } 561 } 562 563 public static class ShortcutActivity extends Activity { 564 } 565 566 public static class ShortcutActivity2 extends Activity { 567 } 568 569 public static class ShortcutActivity3 extends Activity { 570 } 571 572 protected Looper mLooper; 573 protected Handler mHandler; 574 575 protected ServiceContext mServiceContext; 576 protected ClientContext mClientContext; 577 578 protected ShortcutServiceTestable mService; 579 protected ShortcutManagerTestable mManager; 580 protected ShortcutServiceInternal mInternal; 581 582 protected LauncherAppImplTestable mLauncherAppImpl; 583 584 // LauncherApps has per-instace state, so we need a differnt instance for each launcher. 585 protected final Map<Pair<Integer, String>, LauncherAppsTestable> 586 mLauncherAppsMap = new HashMap<>(); 587 protected LauncherAppsTestable mLauncherApps; // Current one 588 589 protected File mInjectedFilePathRoot; 590 591 protected boolean mSafeMode; 592 593 protected long mInjectedCurrentTimeMillis; 594 protected long mDeepSleepTime; // Used to calculate "uptimeMillis". 595 596 protected boolean mInjectedIsLowRamDevice; 597 598 protected Locale mInjectedLocale = Locale.ENGLISH; 599 600 protected int mInjectedCallingUid; 601 protected String mInjectedClientPackage; 602 603 protected Map<String, PackageInfo> mInjectedPackages; 604 605 protected Set<PackageWithUser> mUninstalledPackages; 606 protected Set<PackageWithUser> mDisabledPackages; 607 protected Set<PackageWithUser> mEphemeralPackages; 608 protected Set<String> mSystemPackages; 609 610 protected PackageManager mMockPackageManager; 611 protected PackageManagerInternal mMockPackageManagerInternal; 612 protected UserManager mMockUserManager; 613 protected UserManagerInternal mMockUserManagerInternal; 614 protected UsageStatsManagerInternal mMockUsageStatsManagerInternal; 615 protected ActivityManagerInternal mMockActivityManagerInternal; 616 617 protected static final String CALLING_PACKAGE_1 = "com.android.test.1"; 618 protected static final int CALLING_UID_1 = 10001; 619 620 protected static final String CALLING_PACKAGE_2 = "com.android.test.2"; 621 protected static final int CALLING_UID_2 = 10002; 622 623 protected static final String CALLING_PACKAGE_3 = "com.android.test.3"; 624 protected static final int CALLING_UID_3 = 10003; 625 626 protected static final String CALLING_PACKAGE_4 = "com.android.test.4"; 627 protected static final int CALLING_UID_4 = 10004; 628 629 protected static final String LAUNCHER_1 = "com.android.launcher.1"; 630 protected static final int LAUNCHER_UID_1 = 10011; 631 632 protected static final String LAUNCHER_2 = "com.android.launcher.2"; 633 protected static final int LAUNCHER_UID_2 = 10012; 634 635 protected static final String LAUNCHER_3 = "com.android.launcher.3"; 636 protected static final int LAUNCHER_UID_3 = 10013; 637 638 protected static final String LAUNCHER_4 = "com.android.launcher.4"; 639 protected static final int LAUNCHER_UID_4 = 10014; 640 641 protected static final int USER_0 = UserHandle.USER_SYSTEM; 642 protected static final int USER_10 = 10; 643 protected static final int USER_11 = 11; 644 protected static final int USER_P0 = 20; // profile of user 0 (MANAGED_PROFILE *not* set) 645 protected static final int USER_P1 = 21; // another profile of user 0 (MANAGED_PROFILE set) 646 647 protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0); 648 protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10); 649 protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11); 650 protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0); 651 protected static final UserHandle HANDLE_USER_P1 = UserHandle.of(USER_P1); 652 653 protected static final UserInfo USER_INFO_0 = withProfileGroupId( 654 new UserInfo(USER_0, "user0", 655 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 0); 656 657 protected static final UserInfo USER_INFO_10 = 658 new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED); 659 660 protected static final UserInfo USER_INFO_11 = 661 new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED); 662 663 /* 664 * Cheat: USER_P0 is a sub profile of USER_0, but it doesn't have the MANAGED_PROFILE flag set. 665 * Due to a change made to LauncherApps (b/34340531), work profile apps a no longer able 666 * to see the main profile, which would break tons of unit tests. We avoid it by not setting 667 * MANAGED_PROFILE for P0. 668 * We cover this negative case in CTS. (i.e. CTS has tests to make sure maanged profile 669 * can't access main profile's shortcuts.) 670 */ 671 protected static final UserInfo USER_INFO_P0 = withProfileGroupId( 672 new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), 0); 673 674 protected static final UserInfo USER_INFO_P1 = withProfileGroupId( 675 new UserInfo(USER_P1, "userP1", 676 UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE), 0); 677 678 protected BiPredicate<String, Integer> mDefaultLauncherChecker = 679 (callingPackage, userId) -> 680 LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage) 681 || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage); 682 683 private final Map<Integer, ComponentName> mDefaultLauncher = new ArrayMap<>(); 684 685 protected BiPredicate<ComponentName, Integer> mMainActivityChecker = 686 (activity, userId) -> true; 687 688 protected BiFunction<String, Integer, ComponentName> mMainActivityFetcher = 689 (packageName, userId) -> new ComponentName(packageName, MAIN_ACTIVITY_CLASS); 690 691 protected BiFunction<String, Integer, ComponentName> mPinConfirmActivityFetcher = 692 (packageName, userId) -> new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS); 693 694 protected BiPredicate<ComponentName, Integer> mEnabledActivityChecker 695 = (activity, userId) -> true; // all activities are enabled. 696 697 protected static final long START_TIME = 1440000000101L; 698 699 protected static final long INTERVAL = 10000; 700 701 protected static final int MAX_SHORTCUTS = 10; 702 703 protected static final int MAX_UPDATES_PER_INTERVAL = 3; 704 705 protected static final int MAX_ICON_DIMENSION = 128; 706 707 protected static final int MAX_ICON_DIMENSION_LOWRAM = 32; 708 709 protected static final ShortcutQuery QUERY_ALL = new ShortcutQuery(); 710 711 protected final ArrayList<String> mCallerPermissions = new ArrayList<>(); 712 713 protected final HashMap<String, LinkedHashMap<ComponentName, Integer>> mActivityMetadataResId 714 = new HashMap<>(); 715 716 protected final Map<Integer, UserInfo> mUserInfos = new HashMap<>(); 717 protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>(); 718 protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>(); 719 720 protected static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher"; 721 protected static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name"; 722 protected static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0; 723 724 protected static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings"; 725 protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback"; 726 protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999; 727 728 protected String mInjectedBuildFingerprint = "build1"; 729 730 protected boolean mInjectCheckAccessShortcutsPermission = false; 731 732 protected boolean mInjectHasUnlimitedShortcutsApiCallsPermission = false; 733 734 static { 735 QUERY_ALL.setQueryFlags( 736 ShortcutQuery.FLAG_GET_ALL_KINDS); 737 } 738 739 @Override 740 protected void setUp() throws Exception { 741 super.setUp(); 742 743 mLooper = Looper.getMainLooper(); 744 mHandler = new Handler(mLooper); 745 746 mServiceContext = spy(new ServiceContext()); 747 mClientContext = new ClientContext(); 748 749 mMockPackageManager = mock(PackageManager.class); 750 mMockPackageManagerInternal = mock(PackageManagerInternal.class); 751 mMockUserManager = mock(UserManager.class); 752 mMockUserManagerInternal = mock(UserManagerInternal.class); 753 mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class); 754 mMockActivityManagerInternal = mock(ActivityManagerInternal.class); 755 756 LocalServices.removeServiceForTest(PackageManagerInternal.class); 757 LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal); 758 LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); 759 LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal); 760 LocalServices.removeServiceForTest(ActivityManagerInternal.class); 761 LocalServices.addService(ActivityManagerInternal.class, mMockActivityManagerInternal); 762 LocalServices.removeServiceForTest(UserManagerInternal.class); 763 LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); 764 765 // Prepare injection values. 766 767 mInjectedCurrentTimeMillis = START_TIME; 768 769 mInjectedPackages = new HashMap<>(); 770 addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1); 771 addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2); 772 addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3); 773 addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10); 774 addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4); 775 addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5); 776 addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6); 777 addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10); 778 779 // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target. 780 updatePackageInfo(CALLING_PACKAGE_3, 781 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); 782 updatePackageInfo(LAUNCHER_3, 783 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); 784 785 mUninstalledPackages = new HashSet<>(); 786 mDisabledPackages = new HashSet<>(); 787 mSystemPackages = new HashSet<>(); 788 mEphemeralPackages = new HashSet<>(); 789 790 mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files"); 791 792 deleteAllSavedFiles(); 793 794 // Set up users. 795 mUserInfos.put(USER_0, USER_INFO_0); 796 mUserInfos.put(USER_10, USER_INFO_10); 797 mUserInfos.put(USER_11, USER_INFO_11); 798 mUserInfos.put(USER_P0, USER_INFO_P0); 799 mUserInfos.put(USER_P1, USER_INFO_P1); 800 801 when(mMockUserManagerInternal.isUserUnlockingOrUnlocked(anyInt())) 802 .thenAnswer(inv -> { 803 final int userId = (Integer) inv.getArguments()[0]; 804 return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId)); 805 }); 806 when(mMockUserManagerInternal.getProfileParentId(anyInt())) 807 .thenAnswer(inv -> { 808 final int userId = (Integer) inv.getArguments()[0]; 809 final UserInfo ui = mUserInfos.get(userId); 810 assertNotNull(ui); 811 if (ui.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) { 812 return userId; 813 } 814 final UserInfo parent = mUserInfos.get(ui.profileGroupId); 815 assertNotNull(parent); 816 return parent.id; 817 }); 818 819 when(mMockUserManagerInternal.isProfileAccessible(anyInt(), anyInt(), anyString(), 820 anyBoolean())).thenAnswer(inv -> { 821 final int callingUserId = (Integer) inv.getArguments()[0]; 822 final int targetUserId = (Integer) inv.getArguments()[1]; 823 if (targetUserId == callingUserId) { 824 return true; 825 } 826 final UserInfo callingUserInfo = mUserInfos.get(callingUserId); 827 final UserInfo targetUserInfo = mUserInfos.get(targetUserId); 828 if (callingUserInfo == null || callingUserInfo.isManagedProfile() 829 || targetUserInfo == null || !targetUserInfo.isEnabled()) { 830 return false; 831 } 832 if (targetUserInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID 833 && targetUserInfo.profileGroupId == callingUserInfo.profileGroupId) { 834 return true; 835 } 836 final boolean isExternal = (Boolean) inv.getArguments()[3]; 837 if (!isExternal) { 838 return false; 839 } 840 throw new SecurityException(inv.getArguments()[2] + " for unrelated profile " 841 + targetUserId); 842 }); 843 844 when(mMockUserManager.getUserInfo(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( 845 inv -> mUserInfos.get((Integer) inv.getArguments()[0]))); 846 when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn( 847 ActivityManager.PROCESS_STATE_CACHED_EMPTY); 848 849 // User 0 and P0 are always running 850 mRunningUsers.put(USER_0, true); 851 mRunningUsers.put(USER_10, false); 852 mRunningUsers.put(USER_11, false); 853 mRunningUsers.put(USER_P0, true); 854 mRunningUsers.put(USER_P1, true); 855 856 // Unlock all users by default. 857 mUnlockedUsers.put(USER_0, true); 858 mUnlockedUsers.put(USER_10, true); 859 mUnlockedUsers.put(USER_11, true); 860 mUnlockedUsers.put(USER_P0, true); 861 mUnlockedUsers.put(USER_P1, true); 862 863 // Set up resources 864 setUpAppResources(); 865 866 // Start the service. 867 initService(); 868 setCaller(CALLING_PACKAGE_1); 869 870 if (ENABLE_DUMP) { 871 Log.d(TAG, "setUp done"); 872 } 873 } 874 875 /** 876 * Returns a boolean but also checks if the current UID is SYSTEM_UID. 877 */ 878 protected class AnswerWithSystemCheck<T> implements Answer<T> { 879 private final Function<InvocationOnMock, T> mChecker; 880 881 public AnswerWithSystemCheck(Function<InvocationOnMock, T> checker) { 882 mChecker = checker; 883 } 884 885 @Override 886 public T answer(InvocationOnMock invocation) throws Throwable { 887 assertEquals("Must be called on SYSTEM UID.", 888 Process.SYSTEM_UID, mInjectedCallingUid); 889 return mChecker.apply(invocation); 890 } 891 } 892 893 private static boolean b(Boolean value) { 894 return (value != null && value); 895 } 896 897 protected void setUpAppResources() throws Exception { 898 setUpAppResources(/* offset = */ 0); 899 } 900 901 protected void setUpAppResources(int ressIdOffset) throws Exception { 902 // ressIdOffset is used to adjust resource IDs to emulate the case where an updated app 903 // has resource IDs changed. 904 905 doAnswer(pmInvocation -> { 906 assertEquals(Process.SYSTEM_UID, mInjectedCallingUid); 907 908 final String packageName = (String) pmInvocation.getArguments()[0]; 909 final int userId = (Integer) pmInvocation.getArguments()[1]; 910 911 final Resources res = mock(Resources.class); 912 913 doAnswer(resInvocation -> { 914 final int argResId = (Integer) resInvocation.getArguments()[0]; 915 916 return "string-" + packageName + "-user:" + userId + "-res:" + argResId 917 + "/" + mInjectedLocale; 918 }).when(res).getString(anyInt()); 919 920 doAnswer(resInvocation -> { 921 final int resId = (Integer) resInvocation.getArguments()[0]; 922 923 // Always use the "string" resource type. The type doesn't matter during the test. 924 return packageName + ":string/r" + resId; 925 }).when(res).getResourceName(anyInt()); 926 927 doAnswer(resInvocation -> { 928 final String argResName = (String) resInvocation.getArguments()[0]; 929 final String argType = (String) resInvocation.getArguments()[1]; 930 final String argPackageName = (String) resInvocation.getArguments()[2]; 931 932 // See the above code. getResourceName() will just use "r" + res ID as the entry 933 // name. 934 String entryName = argResName; 935 if (entryName.contains("/")) { 936 entryName = ShortcutInfo.getResourceEntryName(entryName); 937 } 938 return Integer.parseInt(entryName.substring(1)) + ressIdOffset; 939 }).when(res).getIdentifier(anyStringOrNull(), anyStringOrNull(), anyStringOrNull()); 940 return res; 941 }).when(mMockPackageManager).getResourcesForApplicationAsUser(anyString(), anyInt()); 942 } 943 944 protected static UserInfo withProfileGroupId(UserInfo in, int groupId) { 945 in.profileGroupId = groupId; 946 return in; 947 } 948 949 @Override 950 protected void tearDown() throws Exception { 951 if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown"); 952 953 shutdownServices(); 954 955 super.tearDown(); 956 } 957 958 protected Context getTestContext() { 959 return getInstrumentation().getContext(); 960 } 961 962 protected ShortcutManager getManager() { 963 return mManager; 964 } 965 966 protected void deleteAllSavedFiles() { 967 // Empty the data directory. 968 if (mInjectedFilePathRoot.exists()) { 969 Assert.assertTrue("failed to delete dir", 970 FileUtils.deleteContents(mInjectedFilePathRoot)); 971 } 972 mInjectedFilePathRoot.mkdirs(); 973 } 974 975 /** (Re-) init the manager and the service. */ 976 protected void initService() { 977 shutdownServices(); 978 979 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 980 981 // Instantiate targets. 982 mService = new ShortcutServiceTestable(mServiceContext, mLooper); 983 mManager = new ShortcutManagerTestable(mClientContext, mService); 984 985 mInternal = LocalServices.getService(ShortcutServiceInternal.class); 986 987 mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext); 988 mLauncherApps = null; 989 mLauncherAppsMap.clear(); 990 991 // Send boot sequence events. 992 mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY); 993 994 mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 995 } 996 997 protected void shutdownServices() { 998 if (mService != null) { 999 // Flush all the unsaved data from the previous instance. 1000 mService.saveDirtyInfo(); 1001 1002 // Make sure everything is consistent. 1003 mService.verifyStates(); 1004 } 1005 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 1006 1007 mService = null; 1008 mManager = null; 1009 mInternal = null; 1010 mLauncherAppImpl = null; 1011 mLauncherApps = null; 1012 mLauncherAppsMap.clear(); 1013 } 1014 1015 protected void runOnHandler(Runnable r) { 1016 final long token = mServiceContext.injectClearCallingIdentity(); 1017 try { 1018 r.run(); 1019 } finally { 1020 mServiceContext.injectRestoreCallingIdentity(token); 1021 } 1022 } 1023 1024 protected void addPackage(String packageName, int uid, int version) { 1025 addPackage(packageName, uid, version, packageName); 1026 } 1027 1028 protected Signature[] genSignatures(String... signatures) { 1029 final Signature[] sigs = new Signature[signatures.length]; 1030 for (int i = 0; i < signatures.length; i++){ 1031 sigs[i] = new Signature(signatures[i].getBytes()); 1032 } 1033 return sigs; 1034 } 1035 1036 protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) { 1037 final PackageInfo pi = new PackageInfo(); 1038 pi.packageName = packageName; 1039 pi.applicationInfo = new ApplicationInfo(); 1040 pi.applicationInfo.uid = uid; 1041 pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED 1042 | ApplicationInfo.FLAG_ALLOW_BACKUP; 1043 pi.versionCode = version; 1044 pi.applicationInfo.setVersionCode(version); 1045 pi.signatures = null; 1046 pi.signingInfo = new SigningInfo( 1047 new PackageParser.SigningDetails( 1048 genSignatures(signatures), 1049 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 1050 null, 1051 null, 1052 null)); 1053 return pi; 1054 } 1055 1056 protected void addPackage(String packageName, int uid, int version, String... signatures) { 1057 mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures)); 1058 } 1059 1060 protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) { 1061 c.accept(mInjectedPackages.get(packageName)); 1062 } 1063 1064 protected void updatePackageVersion(String packageName, int increment) { 1065 updatePackageInfo(packageName, pi -> { 1066 pi.versionCode += increment; 1067 pi.applicationInfo.setVersionCode(pi.applicationInfo.longVersionCode + increment); 1068 }); 1069 } 1070 1071 protected void updatePackageLastUpdateTime(String packageName, long increment) { 1072 updatePackageInfo(packageName, pi -> { 1073 pi.lastUpdateTime += increment; 1074 }); 1075 } 1076 1077 protected void setPackageLastUpdateTime(String packageName, long value) { 1078 updatePackageInfo(packageName, pi -> { 1079 pi.lastUpdateTime = value; 1080 }); 1081 } 1082 1083 protected void uninstallPackage(int userId, String packageName) { 1084 if (ENABLE_DUMP) { 1085 Log.v(TAG, "Uninstall package " + packageName + " / " + userId); 1086 } 1087 mUninstalledPackages.add(PackageWithUser.of(userId, packageName)); 1088 } 1089 1090 protected void installPackage(int userId, String packageName) { 1091 if (ENABLE_DUMP) { 1092 Log.v(TAG, "Install package " + packageName + " / " + userId); 1093 } 1094 mUninstalledPackages.remove(PackageWithUser.of(userId, packageName)); 1095 } 1096 1097 protected void disablePackage(int userId, String packageName) { 1098 if (ENABLE_DUMP) { 1099 Log.v(TAG, "Disable package " + packageName + " / " + userId); 1100 } 1101 mDisabledPackages.add(PackageWithUser.of(userId, packageName)); 1102 } 1103 1104 protected void enablePackage(int userId, String packageName) { 1105 if (ENABLE_DUMP) { 1106 Log.v(TAG, "Enable package " + packageName + " / " + userId); 1107 } 1108 mDisabledPackages.remove(PackageWithUser.of(userId, packageName)); 1109 } 1110 1111 PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId, 1112 boolean getSignatures) { 1113 final PackageInfo pi = mInjectedPackages.get(packageName); 1114 if (pi == null) return null; 1115 1116 final PackageInfo ret = new PackageInfo(); 1117 ret.packageName = pi.packageName; 1118 ret.versionCode = pi.versionCode; 1119 ret.versionCodeMajor = pi.versionCodeMajor; 1120 ret.lastUpdateTime = pi.lastUpdateTime; 1121 1122 ret.applicationInfo = new ApplicationInfo(pi.applicationInfo); 1123 ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid); 1124 ret.applicationInfo.packageName = pi.packageName; 1125 1126 if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) { 1127 ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; 1128 } 1129 if (mEphemeralPackages.contains(PackageWithUser.of(userId, packageName))) { 1130 ret.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT; 1131 } 1132 if (mSystemPackages.contains(packageName)) { 1133 ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; 1134 } 1135 ret.applicationInfo.enabled = 1136 !mDisabledPackages.contains(PackageWithUser.of(userId, packageName)); 1137 1138 if (getSignatures) { 1139 ret.signatures = null; 1140 ret.signingInfo = pi.signingInfo; 1141 } 1142 1143 return ret; 1144 } 1145 1146 protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) { 1147 if (pi != null && pi.applicationInfo != null) { 1148 list.add(pi.applicationInfo); 1149 } 1150 } 1151 1152 protected List<ApplicationInfo> getInstalledApplications(int userId) { 1153 final ArrayList<ApplicationInfo> ret = new ArrayList<>(); 1154 1155 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); 1156 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret); 1157 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret); 1158 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret); 1159 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret); 1160 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret); 1161 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret); 1162 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret); 1163 1164 return ret; 1165 } 1166 1167 private void addPackageInfo(PackageInfo pi, List<PackageInfo> list) { 1168 if (pi != null) { 1169 list.add(pi); 1170 } 1171 } 1172 1173 private List<PackageInfo> getInstalledPackagesWithUninstalled(int userId) { 1174 final ArrayList<PackageInfo> ret = new ArrayList<>(); 1175 1176 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); 1177 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret); 1178 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret); 1179 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret); 1180 addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret); 1181 addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret); 1182 addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret); 1183 addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret); 1184 1185 return ret; 1186 } 1187 1188 protected void addManifestShortcutResource(ComponentName activity, int resId) { 1189 final String packageName = activity.getPackageName(); 1190 LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName); 1191 if (map == null) { 1192 map = new LinkedHashMap<>(); 1193 mActivityMetadataResId.put(packageName, map); 1194 } 1195 map.put(activity, resId); 1196 } 1197 1198 protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) { 1199 final PackageInfo ret = getInjectedPackageInfo(packageName, userId, 1200 /* getSignatures=*/ false); 1201 1202 final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName); 1203 if (activities != null) { 1204 final ArrayList<ActivityInfo> list = new ArrayList<>(); 1205 1206 for (ComponentName cn : activities.keySet()) { 1207 ActivityInfo ai = new ActivityInfo(); 1208 ai.packageName = cn.getPackageName(); 1209 ai.name = cn.getClassName(); 1210 ai.metaData = new Bundle(); 1211 ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn)); 1212 ai.applicationInfo = ret.applicationInfo; 1213 list.add(ai); 1214 } 1215 ret.activities = list.toArray(new ActivityInfo[list.size()]); 1216 } 1217 return ret; 1218 } 1219 1220 protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) { 1221 if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) { 1222 return null; 1223 } 1224 final int resId = activityInfo.metaData.getInt(key); 1225 return getTestContext().getResources().getXml(resId); 1226 } 1227 1228 /** Replace the current calling package */ 1229 protected void setCaller(String packageName, int userId) { 1230 mInjectedClientPackage = packageName; 1231 mInjectedCallingUid = 1232 Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false), 1233 "Unknown package").applicationInfo.uid; 1234 1235 // Set up LauncherApps for this caller. 1236 final Pair<Integer, String> key = Pair.create(userId, packageName); 1237 if (!mLauncherAppsMap.containsKey(key)) { 1238 mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl)); 1239 } 1240 mLauncherApps = mLauncherAppsMap.get(key); 1241 } 1242 1243 protected void setCaller(String packageName) { 1244 setCaller(packageName, UserHandle.USER_SYSTEM); 1245 } 1246 1247 protected String getCallingPackage() { 1248 return mInjectedClientPackage; 1249 } 1250 1251 /** 1252 * This controls {@link ShortcutService#hasShortcutHostPermission}, but 1253 * not {@link ShortcutService#getDefaultLauncher(int)}. To control the later, use 1254 * {@link #setDefaultLauncher(int, ComponentName)}. 1255 */ 1256 protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) { 1257 mDefaultLauncherChecker = p; 1258 } 1259 1260 /** 1261 * Set the default launcher. This will update {@link #mDefaultLauncherChecker} set by 1262 * {@link #setDefaultLauncherChecker} too. 1263 */ 1264 protected void setDefaultLauncher(int userId, ComponentName launcherActivity) { 1265 mDefaultLauncher.put(userId, launcherActivity); 1266 1267 final BiPredicate<String, Integer> oldChecker = mDefaultLauncherChecker; 1268 mDefaultLauncherChecker = (checkPackageName, checkUserId) -> { 1269 if ((checkUserId == userId) && (launcherActivity != null)) { 1270 return launcherActivity.getPackageName().equals(checkPackageName); 1271 } 1272 return oldChecker.test(checkPackageName, checkUserId); 1273 }; 1274 } 1275 1276 protected void runWithCaller(String packageName, int userId, Runnable r) { 1277 final String previousPackage = mInjectedClientPackage; 1278 final int previousUserId = UserHandle.getUserId(mInjectedCallingUid); 1279 1280 setCaller(packageName, userId); 1281 1282 r.run(); 1283 1284 setCaller(previousPackage, previousUserId); 1285 } 1286 1287 protected void runWithSystemUid(Runnable r) { 1288 final int origUid = mInjectedCallingUid; 1289 mInjectedCallingUid = Process.SYSTEM_UID; 1290 r.run(); 1291 mInjectedCallingUid = origUid; 1292 } 1293 1294 protected void lookupAndFillInResourceNames(ShortcutInfo si) { 1295 runWithSystemUid(() -> si.lookupAndFillInResourceNames( 1296 mService.injectGetResourcesForApplicationAsUser(si.getPackage(), si.getUserId()))); 1297 } 1298 1299 protected int getCallingUserId() { 1300 return UserHandle.getUserId(mInjectedCallingUid); 1301 } 1302 1303 protected UserHandle getCallingUser() { 1304 return UserHandle.of(getCallingUserId()); 1305 } 1306 1307 /** For debugging */ 1308 protected void dumpsysOnLogcat() { 1309 dumpsysOnLogcat(""); 1310 } 1311 1312 protected void dumpsysOnLogcat(String message) { 1313 dumpsysOnLogcat(message, false); 1314 } 1315 1316 protected void dumpsysOnLogcat(String message, boolean force) { 1317 if (force || !ENABLE_DUMP) return; 1318 1319 Log.v(TAG, "Dumping ShortcutService: " + message); 1320 for (String line : dumpsys("-u").split("\n")) { 1321 Log.v(TAG, line); 1322 } 1323 } 1324 1325 protected String dumpCheckin() { 1326 return dumpsys("--checkin"); 1327 } 1328 1329 protected String dumpsys(String... args) { 1330 final ArrayList<String> origPermissions = new ArrayList<>(mCallerPermissions); 1331 mCallerPermissions.add(android.Manifest.permission.DUMP); 1332 try { 1333 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 1334 final PrintWriter pw = new PrintWriter(out); 1335 mService.dumpNoCheck(/* fd */ null, pw, args); 1336 pw.close(); 1337 1338 return out.toString(); 1339 } finally { 1340 mCallerPermissions.clear(); 1341 mCallerPermissions.addAll(origPermissions); 1342 } 1343 } 1344 1345 /** 1346 * For debugging, dump arbitrary file on logcat. 1347 */ 1348 protected void dumpFileOnLogcat(String path) { 1349 dumpFileOnLogcat(path, ""); 1350 } 1351 1352 protected void dumpFileOnLogcat(String path, String message) { 1353 if (!ENABLE_DUMP) return; 1354 1355 Log.v(TAG, "Dumping file: " + path + " " + message); 1356 final StringBuilder sb = new StringBuilder(); 1357 try (BufferedReader br = new BufferedReader(new FileReader(path))) { 1358 String line; 1359 while ((line = br.readLine()) != null) { 1360 Log.v(TAG, line); 1361 } 1362 } catch (Exception e) { 1363 Log.e(TAG, "Couldn't read file", e); 1364 fail("Exception " + e); 1365 } 1366 } 1367 1368 /** 1369 * For debugging, dump the main state file on logcat. 1370 */ 1371 protected void dumpBaseStateFile() { 1372 mService.saveDirtyInfo(); 1373 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath() 1374 + "/system/" + ShortcutService.FILENAME_BASE_STATE); 1375 } 1376 1377 /** 1378 * For debugging, dump per-user state file on logcat. 1379 */ 1380 protected void dumpUserFile(int userId) { 1381 dumpUserFile(userId, ""); 1382 } 1383 1384 protected void dumpUserFile(int userId, String message) { 1385 mService.saveDirtyInfo(); 1386 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath() 1387 + "/user-" + userId 1388 + "/" + ShortcutService.FILENAME_USER_PACKAGES, message); 1389 } 1390 1391 /** 1392 * Make a shortcut with an ID only. 1393 */ 1394 protected ShortcutInfo makeShortcutIdOnly(String id) { 1395 return new ShortcutInfo.Builder(mClientContext, id).build(); 1396 } 1397 1398 /** 1399 * Make a shortcut with an ID. 1400 */ 1401 protected ShortcutInfo makeShortcut(String id) { 1402 return makeShortcut( 1403 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1404 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1405 } 1406 1407 @Deprecated // Title was renamed to short label. 1408 protected ShortcutInfo makeShortcutWithTitle(String id, String title) { 1409 return makeShortcut( 1410 id, title, /* activity =*/ null, /* icon =*/ null, 1411 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1412 } 1413 1414 protected ShortcutInfo makeShortcutWithShortLabel(String id, String shortLabel) { 1415 return makeShortcut( 1416 id, shortLabel, /* activity =*/ null, /* icon =*/ null, 1417 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1418 } 1419 1420 /** 1421 * Make a shortcut with an ID and timestamp. 1422 */ 1423 protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) { 1424 final ShortcutInfo s = makeShortcut( 1425 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1426 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1427 s.setTimestamp(timestamp); 1428 return s; 1429 } 1430 1431 /** 1432 * Make a shortcut with an ID, a timestamp and an activity component 1433 */ 1434 protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp, 1435 ComponentName activity) { 1436 final ShortcutInfo s = makeShortcut( 1437 id, "Title-" + id, activity, /* icon =*/ null, 1438 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1439 s.setTimestamp(timestamp); 1440 return s; 1441 } 1442 1443 /** 1444 * Make a shortcut with an ID and icon. 1445 */ 1446 protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) { 1447 return makeShortcut( 1448 id, "Title-" + id, /* activity =*/ null, icon, 1449 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1450 } 1451 1452 protected ShortcutInfo makePackageShortcut(String packageName, String id) { 1453 String origCaller = getCallingPackage(); 1454 1455 setCaller(packageName); 1456 ShortcutInfo s = makeShortcut( 1457 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1458 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1459 setCaller(origCaller); // restore the caller 1460 1461 return s; 1462 } 1463 1464 /** 1465 * Make multiple shortcuts with IDs. 1466 */ 1467 protected List<ShortcutInfo> makeShortcuts(String... ids) { 1468 final ArrayList<ShortcutInfo> ret = new ArrayList(); 1469 for (String id : ids) { 1470 ret.add(makeShortcut(id)); 1471 } 1472 return ret; 1473 } 1474 1475 protected ShortcutInfo.Builder makeShortcutBuilder() { 1476 return new ShortcutInfo.Builder(mClientContext); 1477 } 1478 1479 protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) { 1480 return makeShortcut( 1481 id, "Title-" + id, activity, /* icon =*/ null, 1482 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1483 } 1484 1485 protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) { 1486 return makeShortcut( 1487 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1488 intent, /* rank =*/ 0); 1489 } 1490 1491 protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity, 1492 String title) { 1493 return makeShortcut( 1494 id, title, activity, /* icon =*/ null, 1495 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1496 } 1497 1498 protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity, 1499 int rank) { 1500 return makeShortcut( 1501 id, "Title-" + id, activity, /* icon =*/ null, 1502 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank); 1503 } 1504 1505 /** 1506 * Make a shortcut with details. 1507 */ 1508 protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity, 1509 Icon icon, Intent intent, int rank) { 1510 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id) 1511 .setActivity(new ComponentName(mClientContext.getPackageName(), "main")) 1512 .setShortLabel(title) 1513 .setRank(rank) 1514 .setIntent(intent); 1515 if (icon != null) { 1516 b.setIcon(icon); 1517 } 1518 if (activity != null) { 1519 b.setActivity(activity); 1520 } 1521 final ShortcutInfo s = b.build(); 1522 1523 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK 1524 1525 return s; 1526 } 1527 1528 protected ShortcutInfo makeShortcutWithIntents(String id, Intent... intents) { 1529 return makeShortcut( 1530 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1531 intents, /* rank =*/ 0); 1532 } 1533 1534 /** 1535 * Make a shortcut with details. 1536 */ 1537 protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity, 1538 Icon icon, Intent[] intents, int rank) { 1539 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id) 1540 .setActivity(new ComponentName(mClientContext.getPackageName(), "main")) 1541 .setShortLabel(title) 1542 .setRank(rank) 1543 .setIntents(intents); 1544 if (icon != null) { 1545 b.setIcon(icon); 1546 } 1547 if (activity != null) { 1548 b.setActivity(activity); 1549 } 1550 final ShortcutInfo s = b.build(); 1551 1552 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK 1553 1554 return s; 1555 } 1556 1557 /** 1558 * Make a shortcut with details. 1559 */ 1560 protected ShortcutInfo makeShortcutWithExtras(String id, Intent intent, 1561 PersistableBundle extras) { 1562 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id) 1563 .setActivity(new ComponentName(mClientContext.getPackageName(), "main")) 1564 .setShortLabel("title-" + id) 1565 .setExtras(extras) 1566 .setIntent(intent); 1567 final ShortcutInfo s = b.build(); 1568 1569 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK 1570 1571 return s; 1572 } 1573 1574 /** 1575 * Make an intent. 1576 */ 1577 protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) { 1578 final Intent intent = new Intent(action); 1579 intent.setComponent(makeComponent(clazz)); 1580 intent.replaceExtras(makeBundle(bundleKeysAndValues)); 1581 return intent; 1582 } 1583 1584 /** 1585 * Make an component name, with the client context. 1586 */ 1587 @NonNull 1588 protected ComponentName makeComponent(Class<?> clazz) { 1589 return new ComponentName(mClientContext, clazz); 1590 } 1591 1592 @NonNull 1593 protected ShortcutInfo findById(List<ShortcutInfo> list, String id) { 1594 for (ShortcutInfo s : list) { 1595 if (s.getId().equals(id)) { 1596 return s; 1597 } 1598 } 1599 fail("Shortcut with id " + id + " not found"); 1600 return null; 1601 } 1602 1603 protected void assertSystem() { 1604 assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid); 1605 } 1606 1607 protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) { 1608 assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked()); 1609 assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked()); 1610 } 1611 1612 public static List<ShortcutInfo> assertAllNotHaveIcon( 1613 List<ShortcutInfo> actualShortcuts) { 1614 for (ShortcutInfo s : actualShortcuts) { 1615 assertNull("ID " + s.getId(), s.getIcon()); 1616 } 1617 return actualShortcuts; 1618 } 1619 1620 @NonNull 1621 protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts, 1622 int shortcutFlags) { 1623 for (ShortcutInfo s : actualShortcuts) { 1624 assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags, 1625 s.hasFlags(shortcutFlags)); 1626 } 1627 return actualShortcuts; 1628 } 1629 1630 protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) { 1631 return mService.getPackageShortcutForTest(packageName, shortcutId, userId); 1632 } 1633 1634 protected void assertShortcutExists(String packageName, String shortcutId, int userId) { 1635 assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null); 1636 } 1637 1638 protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) { 1639 assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null); 1640 } 1641 1642 protected Intent[] launchShortcutAndGetIntentsInner(Runnable shortcutStarter, 1643 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1644 reset(mMockActivityManagerInternal); 1645 shortcutStarter.run(); 1646 1647 final ArgumentCaptor<Intent[]> intentsCaptor = ArgumentCaptor.forClass(Intent[].class); 1648 verify(mMockActivityManagerInternal).startActivitiesAsPackage( 1649 eq(packageName), 1650 eq(userId), 1651 intentsCaptor.capture(), 1652 anyOrNull(Bundle.class)); 1653 return intentsCaptor.getValue(); 1654 } 1655 1656 protected Intent[] launchShortcutAndGetIntents( 1657 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1658 return launchShortcutAndGetIntentsInner( 1659 () -> { 1660 mLauncherApps.startShortcut(packageName, shortcutId, null, null, 1661 UserHandle.of(userId)); 1662 }, packageName, shortcutId, userId 1663 ); 1664 } 1665 1666 protected Intent launchShortcutAndGetIntent( 1667 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1668 final Intent[] intents = launchShortcutAndGetIntents(packageName, shortcutId, userId); 1669 assertEquals(1, intents.length); 1670 return intents[0]; 1671 } 1672 1673 protected Intent[] launchShortcutAndGetIntents_withShortcutInfo( 1674 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1675 return launchShortcutAndGetIntentsInner( 1676 () -> { 1677 mLauncherApps.startShortcut( 1678 getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null); 1679 }, packageName, shortcutId, userId 1680 ); 1681 } 1682 1683 protected Intent launchShortcutAndGetIntent_withShortcutInfo( 1684 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1685 final Intent[] intents = launchShortcutAndGetIntents_withShortcutInfo( 1686 packageName, shortcutId, userId); 1687 assertEquals(1, intents.length); 1688 return intents[0]; 1689 } 1690 1691 protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId, 1692 int userId) { 1693 assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId)); 1694 } 1695 1696 protected void assertShortcutNotLaunched(@NonNull String packageName, 1697 @NonNull String shortcutId, int userId) { 1698 reset(mMockActivityManagerInternal); 1699 try { 1700 mLauncherApps.startShortcut(packageName, shortcutId, null, null, 1701 UserHandle.of(userId)); 1702 fail("ActivityNotFoundException was not thrown"); 1703 } catch (ActivityNotFoundException expected) { 1704 } 1705 // This shouldn't have been called. 1706 verify(mMockActivityManagerInternal, times(0)).startActivitiesAsPackage( 1707 anyString(), 1708 anyInt(), 1709 any(Intent[].class), 1710 anyOrNull(Bundle.class)); 1711 } 1712 1713 protected void assertStartShortcutThrowsException(@NonNull String packageName, 1714 @NonNull String shortcutId, int userId, Class<?> expectedException) { 1715 Exception thrown = null; 1716 try { 1717 mLauncherApps.startShortcut(packageName, shortcutId, null, null, 1718 UserHandle.of(userId)); 1719 } catch (Exception e) { 1720 thrown = e; 1721 } 1722 assertNotNull("Exception was not thrown", thrown); 1723 assertEquals("Exception type different", expectedException, thrown.getClass()); 1724 } 1725 1726 protected void assertBitmapDirectories(int userId, String... expectedDirectories) { 1727 final Set<String> expected = hashSet(set(expectedDirectories)); 1728 1729 final Set<String> actual = new HashSet<>(); 1730 1731 final File[] files = mService.getUserBitmapFilePath(userId).listFiles(); 1732 if (files != null) { 1733 for (File child : files) { 1734 if (child.isDirectory()) { 1735 actual.add(child.getName()); 1736 } 1737 } 1738 } 1739 1740 assertEquals(expected, actual); 1741 } 1742 1743 protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) { 1744 final Set<String> expected = hashSet(set(expectedFiles)); 1745 1746 final Set<String> actual = new HashSet<>(); 1747 1748 final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName) 1749 .listFiles(); 1750 if (files != null) { 1751 for (File child : files) { 1752 if (child.isFile()) { 1753 actual.add(child.getName()); 1754 } 1755 } 1756 } 1757 1758 assertEquals(expected, actual); 1759 } 1760 1761 protected String getBitmapFilename(int userId, String packageName, String shortcutId) { 1762 final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId); 1763 if (si == null) { 1764 return null; 1765 } 1766 mService.waitForBitmapSavesForTest(); 1767 return new File(si.getBitmapPath()).getName(); 1768 } 1769 1770 protected String getBitmapAbsPath(int userId, String packageName, String shortcutId) { 1771 final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId); 1772 if (si == null) { 1773 return null; 1774 } 1775 mService.waitForBitmapSavesForTest(); 1776 return new File(si.getBitmapPath()).getAbsolutePath(); 1777 } 1778 1779 /** 1780 * @return all shortcuts stored internally for the caller. This reflects the *internal* view 1781 * of shortcuts, which may be different from what {@link #getCallerVisibleShortcuts} would 1782 * return, because getCallerVisibleShortcuts() will get shortcuts from the proper "front door" 1783 * which performs some extra checks, like {@link ShortcutPackage#onRestored}. 1784 */ 1785 protected List<ShortcutInfo> getCallerShortcuts() { 1786 final ShortcutPackage p = mService.getPackageShortcutForTest( 1787 getCallingPackage(), getCallingUserId()); 1788 return p == null ? null : p.getAllShortcutsForTest(); 1789 } 1790 1791 /** 1792 * @return all shortcuts owned by caller that are actually visible via ShortcutManager. 1793 * See also {@link #getCallerShortcuts}. 1794 */ 1795 protected List<ShortcutInfo> getCallerVisibleShortcuts() { 1796 final ArrayList<ShortcutInfo> ret = new ArrayList<>(); 1797 ret.addAll(mManager.getDynamicShortcuts()); 1798 ret.addAll(mManager.getPinnedShortcuts()); 1799 ret.addAll(mManager.getManifestShortcuts()); 1800 return ret; 1801 } 1802 1803 protected ShortcutInfo getCallerShortcut(String shortcutId) { 1804 return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId()); 1805 } 1806 1807 protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) { 1808 final List<ShortcutInfo>[] ret = new List[1]; 1809 runWithCaller(launcher, userId, () -> { 1810 final ShortcutQuery q = new ShortcutQuery(); 1811 q.setQueryFlags(queryFlags); 1812 ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId)); 1813 }); 1814 return ret[0]; 1815 } 1816 1817 protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) { 1818 return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED); 1819 } 1820 1821 protected List<ShortcutInfo> getShortcutAsLauncher(int targetUserId) { 1822 final ShortcutQuery q = new ShortcutQuery(); 1823 q.setQueryFlags(ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_DYNAMIC 1824 | ShortcutQuery.FLAG_MATCH_PINNED); 1825 return mLauncherApps.getShortcuts(q, UserHandle.of(targetUserId)); 1826 } 1827 1828 protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId, 1829 int userId) { 1830 final List<ShortcutInfo> infoList = 1831 mLauncherApps.getShortcutInfo(packageName, list(shortcutId), 1832 UserHandle.of(userId)); 1833 assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size()); 1834 return infoList.get(0); 1835 } 1836 1837 protected Intent genPackageAddIntent(String packageName, int userId) { 1838 installPackage(userId, packageName); 1839 1840 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); 1841 i.setData(Uri.parse("package:" + packageName)); 1842 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1843 return i; 1844 } 1845 1846 protected Intent genPackageDeleteIntent(String pakcageName, int userId) { 1847 uninstallPackage(userId, pakcageName); 1848 1849 Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED); 1850 i.setData(Uri.parse("package:" + pakcageName)); 1851 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1852 return i; 1853 } 1854 1855 protected Intent genPackageUpdateIntent(String pakcageName, int userId) { 1856 installPackage(userId, pakcageName); 1857 1858 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); 1859 i.setData(Uri.parse("package:" + pakcageName)); 1860 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1861 i.putExtra(Intent.EXTRA_REPLACING, true); 1862 return i; 1863 } 1864 1865 protected Intent genPackageChangedIntent(String pakcageName, int userId) { 1866 Intent i = new Intent(Intent.ACTION_PACKAGE_CHANGED); 1867 i.setData(Uri.parse("package:" + pakcageName)); 1868 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1869 return i; 1870 } 1871 1872 protected Intent genPackageDataClear(String packageName, int userId) { 1873 Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED); 1874 i.setData(Uri.parse("package:" + packageName)); 1875 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1876 return i; 1877 } 1878 1879 protected void assertExistsAndShadow(ShortcutPackageItem spi) { 1880 assertNotNull(spi); 1881 assertTrue(spi.getPackageInfo().isShadow()); 1882 } 1883 1884 protected File makeFile(File baseDirectory, String... paths) { 1885 File ret = baseDirectory; 1886 1887 for (String path : paths) { 1888 ret = new File(ret, path); 1889 } 1890 1891 return ret; 1892 } 1893 1894 protected boolean bitmapDirectoryExists(String packageName, int userId) { 1895 mService.waitForBitmapSavesForTest(); 1896 final File path = new File(mService.getUserBitmapFilePath(userId), packageName); 1897 return path.isDirectory(); 1898 } 1899 protected static ShortcutQuery buildQuery(long changedSince, 1900 String packageName, ComponentName componentName, 1901 /* @ShortcutQuery.QueryFlags */ int flags) { 1902 return buildQuery(changedSince, packageName, null, componentName, flags); 1903 } 1904 1905 protected static ShortcutQuery buildQuery(long changedSince, 1906 String packageName, List<String> shortcutIds, ComponentName componentName, 1907 /* @ShortcutQuery.QueryFlags */ int flags) { 1908 final ShortcutQuery q = new ShortcutQuery(); 1909 q.setChangedSince(changedSince); 1910 q.setPackage(packageName); 1911 q.setShortcutIds(shortcutIds); 1912 q.setActivity(componentName); 1913 q.setQueryFlags(flags); 1914 return q; 1915 } 1916 1917 protected static ShortcutQuery buildAllQuery(String packageName) { 1918 final ShortcutQuery q = new ShortcutQuery(); 1919 q.setPackage(packageName); 1920 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS); 1921 return q; 1922 } 1923 1924 protected static ShortcutQuery buildPinnedQuery(String packageName) { 1925 final ShortcutQuery q = new ShortcutQuery(); 1926 q.setPackage(packageName); 1927 q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED); 1928 return q; 1929 } 1930 1931 protected static ShortcutQuery buildQueryWithFlags(int queryFlags) { 1932 final ShortcutQuery q = new ShortcutQuery(); 1933 q.setQueryFlags(queryFlags); 1934 return q; 1935 } 1936 1937 protected void backupAndRestore() { 1938 int prevUid = mInjectedCallingUid; 1939 1940 mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it. 1941 1942 dumpsysOnLogcat("Before backup"); 1943 1944 final byte[] payload = mService.getBackupPayload(USER_0); 1945 if (ENABLE_DUMP) { 1946 final String xml = new String(payload); 1947 Log.v(TAG, "Backup payload:"); 1948 for (String line : xml.split("\n")) { 1949 Log.v(TAG, line); 1950 } 1951 } 1952 1953 // Before doing anything else, uninstall all packages. 1954 for (int userId : list(USER_0, USER_P0)) { 1955 for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3, 1956 LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) { 1957 uninstallPackage(userId, pkg); 1958 } 1959 } 1960 1961 shutdownServices(); 1962 1963 deleteAllSavedFiles(); 1964 1965 initService(); 1966 mService.applyRestore(payload, USER_0); 1967 1968 // handleUnlockUser will perform the gone package check, but it shouldn't remove 1969 // shadow information. 1970 mService.handleUnlockUser(USER_0); 1971 1972 dumpsysOnLogcat("After restore"); 1973 1974 mInjectedCallingUid = prevUid; 1975 } 1976 1977 protected void prepareCrossProfileDataSet() { 1978 mRunningUsers.put(USER_10, true); // this test needs user 10. 1979 1980 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { 1981 assertTrue(mManager.setDynamicShortcuts(list( 1982 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1983 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1984 }); 1985 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { 1986 assertTrue(mManager.setDynamicShortcuts(list( 1987 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1988 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1989 }); 1990 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { 1991 assertTrue(mManager.setDynamicShortcuts(list( 1992 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1993 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1994 }); 1995 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { 1996 assertTrue(mManager.setDynamicShortcuts(list())); 1997 }); 1998 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { 1999 assertTrue(mManager.setDynamicShortcuts(list( 2000 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 2001 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 2002 }); 2003 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { 2004 assertTrue(mManager.setDynamicShortcuts(list( 2005 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"), 2006 makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6")))); 2007 }); 2008 2009 runWithCaller(LAUNCHER_1, USER_0, () -> { 2010 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); 2011 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0); 2012 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0); 2013 2014 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0); 2015 }); 2016 runWithCaller(LAUNCHER_2, USER_0, () -> { 2017 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); 2018 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0); 2019 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0); 2020 2021 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0); 2022 }); 2023 2024 // Note LAUNCHER_3 has allowBackup=false. 2025 runWithCaller(LAUNCHER_3, USER_0, () -> { 2026 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); 2027 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0); 2028 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0); 2029 2030 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0); 2031 }); 2032 runWithCaller(LAUNCHER_4, USER_0, () -> { 2033 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0); 2034 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0); 2035 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0); 2036 mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0); 2037 }); 2038 2039 // Launcher on a managed profile is referring ot user 0! 2040 runWithCaller(LAUNCHER_1, USER_P0, () -> { 2041 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0); 2042 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0); 2043 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"), 2044 HANDLE_USER_0); 2045 2046 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0); 2047 }); 2048 runWithCaller(LAUNCHER_1, USER_10, () -> { 2049 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10); 2050 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10); 2051 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"), 2052 HANDLE_USER_10); 2053 }); 2054 2055 // Then remove some dynamic shortcuts. 2056 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { 2057 assertTrue(mManager.setDynamicShortcuts(list( 2058 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 2059 }); 2060 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { 2061 assertTrue(mManager.setDynamicShortcuts(list( 2062 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 2063 }); 2064 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { 2065 assertTrue(mManager.setDynamicShortcuts(list( 2066 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 2067 }); 2068 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { 2069 assertTrue(mManager.setDynamicShortcuts(list())); 2070 }); 2071 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { 2072 assertTrue(mManager.setDynamicShortcuts(list( 2073 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 2074 }); 2075 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { 2076 assertTrue(mManager.setDynamicShortcuts(list( 2077 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3")))); 2078 }); 2079 } 2080 2081 public static List<ShortcutInfo> assertAllHaveIconResId( 2082 List<ShortcutInfo> actualShortcuts) { 2083 for (ShortcutInfo s : actualShortcuts) { 2084 assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource()); 2085 assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile()); 2086 } 2087 return actualShortcuts; 2088 } 2089 2090 public static List<ShortcutInfo> assertAllHaveIconFile( 2091 List<ShortcutInfo> actualShortcuts) { 2092 for (ShortcutInfo s : actualShortcuts) { 2093 assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource()); 2094 assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile()); 2095 } 2096 return actualShortcuts; 2097 } 2098 2099 public static List<ShortcutInfo> assertAllHaveIcon( 2100 List<ShortcutInfo> actualShortcuts) { 2101 for (ShortcutInfo s : actualShortcuts) { 2102 assertTrue("ID " + s.getId() + " has no icon ", 2103 s.hasIconFile() || s.hasIconResource() || s.getIcon() != null); 2104 } 2105 return actualShortcuts; 2106 } 2107 2108 public static List<ShortcutInfo> assertAllStringsResolved( 2109 List<ShortcutInfo> actualShortcuts) { 2110 for (ShortcutInfo s : actualShortcuts) { 2111 assertTrue("ID " + s.getId(), s.hasStringResourcesResolved()); 2112 } 2113 return actualShortcuts; 2114 } 2115 2116 public String readTestAsset(String assetPath) throws IOException { 2117 final StringBuilder sb = new StringBuilder(); 2118 try (BufferedReader br = new BufferedReader( 2119 new InputStreamReader( 2120 getTestContext().getResources().getAssets().open(assetPath)))) { 2121 String line; 2122 while ((line = br.readLine()) != null) { 2123 sb.append(line); 2124 sb.append(System.lineSeparator()); 2125 } 2126 } 2127 return sb.toString(); 2128 } 2129 2130 protected void prepareGetHomeActivitiesAsUser(ComponentName preferred, 2131 List<ResolveInfo> candidates, int userId) { 2132 doAnswer(inv -> { 2133 ((List) inv.getArguments()[0]).addAll(candidates); 2134 return preferred; 2135 }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId)); 2136 } 2137 2138 protected static ComponentName cn(String packageName, String name) { 2139 return new ComponentName(packageName, name); 2140 } 2141 2142 protected static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) { 2143 final ResolveInfo ri = new ResolveInfo(); 2144 ri.activityInfo = new ActivityInfo(); 2145 ri.activityInfo.applicationInfo = new ApplicationInfo(); 2146 2147 ri.activityInfo.packageName = packageName; 2148 ri.activityInfo.name = name; 2149 if (isSystem) { 2150 ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; 2151 } 2152 ri.priority = priority; 2153 return ri; 2154 } 2155 2156 protected static ResolveInfo getSystemLauncher() { 2157 return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true, 2158 PACKAGE_SYSTEM_LAUNCHER_PRIORITY); 2159 } 2160 2161 protected static ResolveInfo getFallbackLauncher() { 2162 return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true, 2163 PACKAGE_FALLBACK_LAUNCHER_PRIORITY); 2164 } 2165 2166 protected void makeUidForeground(int uid) { 2167 try { 2168 mService.mUidObserver.onUidStateChanged( 2169 uid, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); 2170 } catch (RemoteException e) { 2171 e.rethrowAsRuntimeException(); 2172 } 2173 } 2174 2175 protected void makeCallerForeground() { 2176 makeUidForeground(mInjectedCallingUid); 2177 } 2178 2179 protected void makeUidBackground(int uid) { 2180 try { 2181 mService.mUidObserver.onUidStateChanged( 2182 uid, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0); 2183 } catch (RemoteException e) { 2184 e.rethrowAsRuntimeException(); 2185 } 2186 } 2187 2188 protected void makeCallerBackground() { 2189 makeUidBackground(mInjectedCallingUid); 2190 } 2191 2192 protected void publishManifestShortcutsAsCaller(int resId) { 2193 addManifestShortcutResource( 2194 new ComponentName(getCallingPackage(), ShortcutActivity.class.getName()), 2195 resId); 2196 updatePackageVersion(getCallingPackage(), 1); 2197 mService.mPackageMonitor.onReceive(getTestContext(), 2198 genPackageAddIntent(getCallingPackage(), getCallingUserId())); 2199 } 2200 2201 protected void assertFileNotExists(String path) { 2202 final File f = new File(mInjectedFilePathRoot, path); 2203 assertFalse("File shouldn't exist: " + f.getAbsolutePath(), f.exists()); 2204 } 2205 2206 protected void assertFileExistsWithContent(String path) { 2207 final File f = new File(mInjectedFilePathRoot, path); 2208 assertTrue("File should exist: " + f.getAbsolutePath(), f.exists()); 2209 assertTrue("File should be larger than 0b: " + f.getAbsolutePath(), f.length() > 0); 2210 } 2211 } 2212