Loading services/core/java/com/android/server/pm/ShortcutService.java +20 −43 Original line number Diff line number Diff line Loading @@ -131,12 +131,8 @@ import java.util.function.Predicate; * - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi. * -> But TypedValue.applyDimension() doesn't differentiate x and y..? * * - Default launcher check does take a few ms. Worth caching. * * - Detect when already registered instances are passed to APIs again, which might break * internal bitmap handling. * * - Add more call stats. */ public class ShortcutService extends IShortcutService.Stub { static final String TAG = "ShortcutService"; Loading Loading @@ -1354,16 +1350,21 @@ public class ShortcutService extends IShortcutService.Stub { } private void enforceSystemOrShell() { Preconditions.checkState(isCallerSystem() || isCallerShell(), "Caller must be system or shell"); if (!(isCallerSystem() || isCallerShell())) { throw new SecurityException("Caller must be system or shell"); } } private void enforceShell() { Preconditions.checkState(isCallerShell(), "Caller must be shell"); if (!isCallerShell()) { throw new SecurityException("Caller must be shell"); } } private void enforceSystem() { Preconditions.checkState(isCallerSystem(), "Caller must be system"); if (!isCallerSystem()) { throw new SecurityException("Caller must be system"); } } private void enforceResetThrottlingPermission() { Loading Loading @@ -3177,9 +3178,13 @@ public class ShortcutService extends IShortcutService.Stub { enforceShell(); final long token = injectClearCallingIdentity(); try { final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver); resultReceiver.send(status, null); } finally { injectRestoreCallingIdentity(token); } } static class CommandException extends Exception { Loading Loading @@ -3224,9 +3229,6 @@ public class ShortcutService extends IShortcutService.Stub { final PrintWriter pw = getOutPrintWriter(); try { switch (cmd) { case "reset-package-throttling": handleResetPackageThrottling(); break; case "reset-throttling": handleResetThrottling(); break; Loading @@ -3245,9 +3247,6 @@ public class ShortcutService extends IShortcutService.Stub { case "get-default-launcher": handleGetDefaultLauncher(); break; case "refresh-default-launcher": handleRefreshDefaultLauncher(); break; case "unload-user": handleUnloadUser(); break; Loading @@ -3273,9 +3272,6 @@ public class ShortcutService extends IShortcutService.Stub { final PrintWriter pw = getOutPrintWriter(); pw.println("Usage: cmd shortcut COMMAND [options ...]"); pw.println(); pw.println("cmd shortcut reset-package-throttling [--user USER_ID] PACKAGE"); pw.println(" Reset throttling for a package"); pw.println(); pw.println("cmd shortcut reset-throttling [--user USER_ID]"); pw.println(" Reset throttling for all packages and users"); pw.println(); Loading @@ -3292,10 +3288,7 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(" Clear the cached default launcher"); pw.println(); pw.println("cmd shortcut get-default-launcher [--user USER_ID]"); pw.println(" Show the cached default launcher"); pw.println(); pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]"); pw.println(" Refresh the cached default launcher"); pw.println(" Show the default launcher"); pw.println(); pw.println("cmd shortcut unload-user [--user USER_ID]"); pw.println(" Unload a user from the memory"); Loading @@ -3309,7 +3302,7 @@ public class ShortcutService extends IShortcutService.Stub { private void handleResetThrottling() throws CommandException { parseOptions(/* takeUser =*/ true); Slog.i(TAG, "cmd: handleResetThrottling"); Slog.i(TAG, "cmd: handleResetThrottling: user=" + mUserId); resetThrottlingInner(mUserId); } Loading @@ -3320,16 +3313,6 @@ public class ShortcutService extends IShortcutService.Stub { resetAllThrottlingInner(); } private void handleResetPackageThrottling() throws CommandException { parseOptions(/* takeUser =*/ true); final String packageName = getNextArgRequired(); Slog.i(TAG, "cmd: handleResetPackageThrottling: " + packageName); resetPackageThrottling(packageName, mUserId); } private void handleOverrideConfig() throws CommandException { final String config = getNextArgRequired(); Loading Loading @@ -3375,12 +3358,6 @@ public class ShortcutService extends IShortcutService.Stub { private void handleGetDefaultLauncher() throws CommandException { parseOptions(/* takeUser =*/ true); showLauncher(); } private void handleRefreshDefaultLauncher() throws CommandException { parseOptions(/* takeUser =*/ true); clearLauncher(); showLauncher(); } Loading @@ -3388,7 +3365,7 @@ public class ShortcutService extends IShortcutService.Stub { private void handleUnloadUser() throws CommandException { parseOptions(/* takeUser =*/ true); Slog.i(TAG, "cmd: handleUnloadUser: " + mUserId); Slog.i(TAG, "cmd: handleUnloadUser: user=" + mUserId); ShortcutService.this.handleCleanupUser(mUserId); } Loading @@ -3397,7 +3374,7 @@ public class ShortcutService extends IShortcutService.Stub { parseOptions(/* takeUser =*/ true); final String packageName = getNextArgRequired(); Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName); Slog.i(TAG, "cmd: handleClearShortcuts: user" + mUserId + ", " + packageName); ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId, /* appStillExists = */ true); Loading services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +44 −0 Original line number Diff line number Diff line Loading @@ -614,6 +614,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>(); protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>(); protected static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher"; protected static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name"; protected static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0; protected static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings"; protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback"; protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999; static { QUERY_ALL.setQueryFlags( ShortcutQuery.FLAG_GET_ALL_KINDS); Loading Loading @@ -1866,4 +1874,40 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } return sb.toString(); } protected void prepareGetHomeActivitiesAsUser(ComponentName preferred, List<ResolveInfo> candidates, int userId) { doAnswer(inv -> { ((List) inv.getArguments()[0]).addAll(candidates); return preferred; }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId)); } protected static ComponentName cn(String packageName, String name) { return new ComponentName(packageName, name); } protected static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = new ActivityInfo(); ri.activityInfo.applicationInfo = new ApplicationInfo(); ri.activityInfo.packageName = packageName; ri.activityInfo.name = name; if (isSystem) { ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; } ri.priority = priority; return ri; } protected static ResolveInfo getSystemLauncher() { return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true, PACKAGE_SYSTEM_LAUNCHER_PRIORITY); } protected static ResolveInfo getFallbackLauncher() { return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true, PACKAGE_FALLBACK_LAUNCHER_PRIORITY); } } services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +1 −10 Original line number Diff line number Diff line Loading @@ -107,15 +107,6 @@ import java.util.Locale; -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 \ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner * TODO More tests for pinning + manifest shortcuts * TODO Manifest shortcuts + app upgrade -> launcher callback. * Also locale change should trigger launcehr callbacks too, when they use strign resoucres. * (not implemented yet.) * TODO: Add checks with assertAllNotHaveIcon() * TODO: Detailed test for hasShortcutPermissionInner(). * TODO: Add tests for the command line functions too. */ @SmallTest public class ShortcutManagerTest1 extends BaseShortcutManagerTest { Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java +0 −46 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.pm; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; Loading @@ -36,51 +35,6 @@ import java.util.List; */ @SmallTest public class ShortcutManagerTest6 extends BaseShortcutManagerTest { private static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher"; private static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name"; private static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0; private static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings"; private static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback"; private static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999; private void prepareGetHomeActivitiesAsUser(ComponentName preferred, List<ResolveInfo> candidates, int userId) { doAnswer(inv -> { ((List) inv.getArguments()[0]).addAll(candidates); return preferred; }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId)); } private static ComponentName cn(String packageName, String name) { return new ComponentName(packageName, name); } private static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = new ActivityInfo(); ri.activityInfo.applicationInfo = new ApplicationInfo(); ri.activityInfo.packageName = packageName; ri.activityInfo.name = name; if (isSystem) { ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; } ri.priority = priority; return ri; } private static ResolveInfo getSystemLauncher() { return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true, PACKAGE_SYSTEM_LAUNCHER_PRIORITY); } private static ResolveInfo getFallbackLauncher() { return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true, PACKAGE_FALLBACK_LAUNCHER_PRIORITY); } public void testHasShortcutHostPermissionInner_systemLauncherOnly() { // Preferred isn't set, use the system launcher. prepareGetHomeActivitiesAsUser( Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java 0 → 100644 +335 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertContains; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertSuccess; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.readAll; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resultContains; import android.content.ComponentName; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.test.suitebuilder.annotation.SmallTest; import com.android.frameworks.servicestests.R; import com.android.server.pm.ShortcutService.ConfigConstants; import java.io.File; import java.io.IOException; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * Unit test for "cmd shortcut" * * Launcher related commands are tested in */ @SmallTest public class ShortcutManagerTest7 extends BaseShortcutManagerTest { private List<String> callShellCommand(String... args) throws IOException, RemoteException { // For reset to work, the current time needs to be incrementing. mInjectedCurrentTimeMillis++; final AtomicInteger resultCode = new AtomicInteger(Integer.MIN_VALUE); final ResultReceiver rr = new ResultReceiver(mHandler) { @Override public void send(int resultCode_, Bundle resultData) { resultCode.set(resultCode_); } }; final File out = File.createTempFile("shellout-", ".tmp", getTestContext().getCacheDir()); try { try (final ParcelFileDescriptor fd = ParcelFileDescriptor.open(out, ParcelFileDescriptor.MODE_READ_WRITE)) { mService.onShellCommand( /* fdin*/ null, /* fdout*/ fd.getFileDescriptor(), /* fderr*/ fd.getFileDescriptor(), args, rr); } return readAll(out); } finally { out.delete(); } } public void testNonShell() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = 12345; assertExpectException(SecurityException.class, "must be shell", () -> callShellCommand("reset-config")); mInjectedCallingUid = Process.SYSTEM_UID; assertExpectException(SecurityException.class, "must be shell", () -> callShellCommand("reset-config")); assertEquals(99, mService.mMaxUpdatesPerInterval); } public void testRoot() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.ROOT_UID; assertSuccess(callShellCommand("reset-config")); assertEquals(3, mService.mMaxUpdatesPerInterval); } public void testRestConfig() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-config")); assertEquals(3, mService.mMaxUpdatesPerInterval); } public void testOverrideConfig() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("override-config", ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=1")); assertEquals(1, mService.mMaxUpdatesPerInterval); } public void testResetThrottling() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-throttling")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); } public void testResetThrottling_user_not_running() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; assertTrue(resultContains( callShellCommand("reset-throttling", "--user", "10"), "User 10 is not running or locked")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); } public void testResetThrottling_user_running() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-throttling", "--user", "10")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); } public void testResetAllThrottling() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-all-throttling")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); } public void testLauncherCommands() throws Exception { prepareGetHomeActivitiesAsUser( /* preferred */ null, list(getSystemLauncher(), getFallbackLauncher()), USER_0); prepareGetHomeActivitiesAsUser( /* preferred */ cn(CALLING_PACKAGE_2, "name"), list(getSystemLauncher(), getFallbackLauncher(), ri(CALLING_PACKAGE_1, "name", false, 0), ri(CALLING_PACKAGE_2, "name", false, 0) ), USER_10); assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0)); // First, test "get". mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertContains( assertSuccess(callShellCommand("get-default-launcher")), "Launcher: ComponentInfo{com.android.systemlauncher/systemlauncher_name}"); assertContains( assertSuccess(callShellCommand("get-default-launcher", "--user", "10")), "Launcher: ComponentInfo{com.android.test.2/name}"); // Next, test "clear". assertSuccess(callShellCommand("clear-default-launcher", "--user", "10")); // User-10's launcher should be cleared. assertEquals(null, mService.getUserShortcutsLocked(USER_10).getLastKnownLauncher()); assertEquals(null, mService.getUserShortcutsLocked(USER_10).getCachedLauncher()); // but user'0's shouldn't. assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME), mService.getUserShortcutsLocked(USER_0).getCachedLauncher()); // Change user-0's launcher. prepareGetHomeActivitiesAsUser( /* preferred */ cn(CALLING_PACKAGE_1, "name"), list( ri(CALLING_PACKAGE_1, "name", false, 0) ), USER_0); assertContains( assertSuccess(callShellCommand("get-default-launcher")), "Launcher: ComponentInfo{com.android.test.1/name}"); } public void testUnloadUser() throws Exception { prepareCrossProfileDataSet(); assertNotNull(mService.getShortcutsForTest().get(USER_10)); mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("unload-user", "--user", "10")); assertNull(mService.getShortcutsForTest().get(USER_10)); } public void testClearShortcuts() throws Exception { mRunningUsers.put(USER_10, true); // Add two manifests and two dynamics. addManifestShortcutResource( new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.addDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); }); runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() .selectPinned() .haveIds("ms2", "s2"); }); // First, call for a different package. mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_2)); // Shouldn't be cleared yet. runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() .selectPinned() .haveIds("ms2", "s2"); }); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_1)); // Only manifest shortcuts will remain, and are no longer pinned. runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2") .areAllEnabled() .areAllNotPinned(); }); } } Loading
services/core/java/com/android/server/pm/ShortcutService.java +20 −43 Original line number Diff line number Diff line Loading @@ -131,12 +131,8 @@ import java.util.function.Predicate; * - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi. * -> But TypedValue.applyDimension() doesn't differentiate x and y..? * * - Default launcher check does take a few ms. Worth caching. * * - Detect when already registered instances are passed to APIs again, which might break * internal bitmap handling. * * - Add more call stats. */ public class ShortcutService extends IShortcutService.Stub { static final String TAG = "ShortcutService"; Loading Loading @@ -1354,16 +1350,21 @@ public class ShortcutService extends IShortcutService.Stub { } private void enforceSystemOrShell() { Preconditions.checkState(isCallerSystem() || isCallerShell(), "Caller must be system or shell"); if (!(isCallerSystem() || isCallerShell())) { throw new SecurityException("Caller must be system or shell"); } } private void enforceShell() { Preconditions.checkState(isCallerShell(), "Caller must be shell"); if (!isCallerShell()) { throw new SecurityException("Caller must be shell"); } } private void enforceSystem() { Preconditions.checkState(isCallerSystem(), "Caller must be system"); if (!isCallerSystem()) { throw new SecurityException("Caller must be system"); } } private void enforceResetThrottlingPermission() { Loading Loading @@ -3177,9 +3178,13 @@ public class ShortcutService extends IShortcutService.Stub { enforceShell(); final long token = injectClearCallingIdentity(); try { final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver); resultReceiver.send(status, null); } finally { injectRestoreCallingIdentity(token); } } static class CommandException extends Exception { Loading Loading @@ -3224,9 +3229,6 @@ public class ShortcutService extends IShortcutService.Stub { final PrintWriter pw = getOutPrintWriter(); try { switch (cmd) { case "reset-package-throttling": handleResetPackageThrottling(); break; case "reset-throttling": handleResetThrottling(); break; Loading @@ -3245,9 +3247,6 @@ public class ShortcutService extends IShortcutService.Stub { case "get-default-launcher": handleGetDefaultLauncher(); break; case "refresh-default-launcher": handleRefreshDefaultLauncher(); break; case "unload-user": handleUnloadUser(); break; Loading @@ -3273,9 +3272,6 @@ public class ShortcutService extends IShortcutService.Stub { final PrintWriter pw = getOutPrintWriter(); pw.println("Usage: cmd shortcut COMMAND [options ...]"); pw.println(); pw.println("cmd shortcut reset-package-throttling [--user USER_ID] PACKAGE"); pw.println(" Reset throttling for a package"); pw.println(); pw.println("cmd shortcut reset-throttling [--user USER_ID]"); pw.println(" Reset throttling for all packages and users"); pw.println(); Loading @@ -3292,10 +3288,7 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(" Clear the cached default launcher"); pw.println(); pw.println("cmd shortcut get-default-launcher [--user USER_ID]"); pw.println(" Show the cached default launcher"); pw.println(); pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]"); pw.println(" Refresh the cached default launcher"); pw.println(" Show the default launcher"); pw.println(); pw.println("cmd shortcut unload-user [--user USER_ID]"); pw.println(" Unload a user from the memory"); Loading @@ -3309,7 +3302,7 @@ public class ShortcutService extends IShortcutService.Stub { private void handleResetThrottling() throws CommandException { parseOptions(/* takeUser =*/ true); Slog.i(TAG, "cmd: handleResetThrottling"); Slog.i(TAG, "cmd: handleResetThrottling: user=" + mUserId); resetThrottlingInner(mUserId); } Loading @@ -3320,16 +3313,6 @@ public class ShortcutService extends IShortcutService.Stub { resetAllThrottlingInner(); } private void handleResetPackageThrottling() throws CommandException { parseOptions(/* takeUser =*/ true); final String packageName = getNextArgRequired(); Slog.i(TAG, "cmd: handleResetPackageThrottling: " + packageName); resetPackageThrottling(packageName, mUserId); } private void handleOverrideConfig() throws CommandException { final String config = getNextArgRequired(); Loading Loading @@ -3375,12 +3358,6 @@ public class ShortcutService extends IShortcutService.Stub { private void handleGetDefaultLauncher() throws CommandException { parseOptions(/* takeUser =*/ true); showLauncher(); } private void handleRefreshDefaultLauncher() throws CommandException { parseOptions(/* takeUser =*/ true); clearLauncher(); showLauncher(); } Loading @@ -3388,7 +3365,7 @@ public class ShortcutService extends IShortcutService.Stub { private void handleUnloadUser() throws CommandException { parseOptions(/* takeUser =*/ true); Slog.i(TAG, "cmd: handleUnloadUser: " + mUserId); Slog.i(TAG, "cmd: handleUnloadUser: user=" + mUserId); ShortcutService.this.handleCleanupUser(mUserId); } Loading @@ -3397,7 +3374,7 @@ public class ShortcutService extends IShortcutService.Stub { parseOptions(/* takeUser =*/ true); final String packageName = getNextArgRequired(); Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName); Slog.i(TAG, "cmd: handleClearShortcuts: user" + mUserId + ", " + packageName); ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId, /* appStillExists = */ true); Loading
services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +44 −0 Original line number Diff line number Diff line Loading @@ -614,6 +614,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>(); protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>(); protected static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher"; protected static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name"; protected static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0; protected static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings"; protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback"; protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999; static { QUERY_ALL.setQueryFlags( ShortcutQuery.FLAG_GET_ALL_KINDS); Loading Loading @@ -1866,4 +1874,40 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } return sb.toString(); } protected void prepareGetHomeActivitiesAsUser(ComponentName preferred, List<ResolveInfo> candidates, int userId) { doAnswer(inv -> { ((List) inv.getArguments()[0]).addAll(candidates); return preferred; }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId)); } protected static ComponentName cn(String packageName, String name) { return new ComponentName(packageName, name); } protected static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = new ActivityInfo(); ri.activityInfo.applicationInfo = new ApplicationInfo(); ri.activityInfo.packageName = packageName; ri.activityInfo.name = name; if (isSystem) { ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; } ri.priority = priority; return ri; } protected static ResolveInfo getSystemLauncher() { return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true, PACKAGE_SYSTEM_LAUNCHER_PRIORITY); } protected static ResolveInfo getFallbackLauncher() { return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true, PACKAGE_FALLBACK_LAUNCHER_PRIORITY); } }
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +1 −10 Original line number Diff line number Diff line Loading @@ -107,15 +107,6 @@ import java.util.Locale; -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 \ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner * TODO More tests for pinning + manifest shortcuts * TODO Manifest shortcuts + app upgrade -> launcher callback. * Also locale change should trigger launcehr callbacks too, when they use strign resoucres. * (not implemented yet.) * TODO: Add checks with assertAllNotHaveIcon() * TODO: Detailed test for hasShortcutPermissionInner(). * TODO: Add tests for the command line functions too. */ @SmallTest public class ShortcutManagerTest1 extends BaseShortcutManagerTest { Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java +0 −46 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.pm; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; Loading @@ -36,51 +35,6 @@ import java.util.List; */ @SmallTest public class ShortcutManagerTest6 extends BaseShortcutManagerTest { private static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher"; private static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name"; private static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0; private static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings"; private static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback"; private static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999; private void prepareGetHomeActivitiesAsUser(ComponentName preferred, List<ResolveInfo> candidates, int userId) { doAnswer(inv -> { ((List) inv.getArguments()[0]).addAll(candidates); return preferred; }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId)); } private static ComponentName cn(String packageName, String name) { return new ComponentName(packageName, name); } private static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = new ActivityInfo(); ri.activityInfo.applicationInfo = new ApplicationInfo(); ri.activityInfo.packageName = packageName; ri.activityInfo.name = name; if (isSystem) { ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; } ri.priority = priority; return ri; } private static ResolveInfo getSystemLauncher() { return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true, PACKAGE_SYSTEM_LAUNCHER_PRIORITY); } private static ResolveInfo getFallbackLauncher() { return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true, PACKAGE_FALLBACK_LAUNCHER_PRIORITY); } public void testHasShortcutHostPermissionInner_systemLauncherOnly() { // Preferred isn't set, use the system launcher. prepareGetHomeActivitiesAsUser( Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java 0 → 100644 +335 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertContains; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertSuccess; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.readAll; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resultContains; import android.content.ComponentName; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.test.suitebuilder.annotation.SmallTest; import com.android.frameworks.servicestests.R; import com.android.server.pm.ShortcutService.ConfigConstants; import java.io.File; import java.io.IOException; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * Unit test for "cmd shortcut" * * Launcher related commands are tested in */ @SmallTest public class ShortcutManagerTest7 extends BaseShortcutManagerTest { private List<String> callShellCommand(String... args) throws IOException, RemoteException { // For reset to work, the current time needs to be incrementing. mInjectedCurrentTimeMillis++; final AtomicInteger resultCode = new AtomicInteger(Integer.MIN_VALUE); final ResultReceiver rr = new ResultReceiver(mHandler) { @Override public void send(int resultCode_, Bundle resultData) { resultCode.set(resultCode_); } }; final File out = File.createTempFile("shellout-", ".tmp", getTestContext().getCacheDir()); try { try (final ParcelFileDescriptor fd = ParcelFileDescriptor.open(out, ParcelFileDescriptor.MODE_READ_WRITE)) { mService.onShellCommand( /* fdin*/ null, /* fdout*/ fd.getFileDescriptor(), /* fderr*/ fd.getFileDescriptor(), args, rr); } return readAll(out); } finally { out.delete(); } } public void testNonShell() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = 12345; assertExpectException(SecurityException.class, "must be shell", () -> callShellCommand("reset-config")); mInjectedCallingUid = Process.SYSTEM_UID; assertExpectException(SecurityException.class, "must be shell", () -> callShellCommand("reset-config")); assertEquals(99, mService.mMaxUpdatesPerInterval); } public void testRoot() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.ROOT_UID; assertSuccess(callShellCommand("reset-config")); assertEquals(3, mService.mMaxUpdatesPerInterval); } public void testRestConfig() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-config")); assertEquals(3, mService.mMaxUpdatesPerInterval); } public void testOverrideConfig() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("override-config", ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=1")); assertEquals(1, mService.mMaxUpdatesPerInterval); } public void testResetThrottling() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-throttling")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); } public void testResetThrottling_user_not_running() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; assertTrue(resultContains( callShellCommand("reset-throttling", "--user", "10"), "User 10 is not running or locked")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); } public void testResetThrottling_user_running() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-throttling", "--user", "10")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); } public void testResetAllThrottling() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-all-throttling")); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); } public void testLauncherCommands() throws Exception { prepareGetHomeActivitiesAsUser( /* preferred */ null, list(getSystemLauncher(), getFallbackLauncher()), USER_0); prepareGetHomeActivitiesAsUser( /* preferred */ cn(CALLING_PACKAGE_2, "name"), list(getSystemLauncher(), getFallbackLauncher(), ri(CALLING_PACKAGE_1, "name", false, 0), ri(CALLING_PACKAGE_2, "name", false, 0) ), USER_10); assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0)); // First, test "get". mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertContains( assertSuccess(callShellCommand("get-default-launcher")), "Launcher: ComponentInfo{com.android.systemlauncher/systemlauncher_name}"); assertContains( assertSuccess(callShellCommand("get-default-launcher", "--user", "10")), "Launcher: ComponentInfo{com.android.test.2/name}"); // Next, test "clear". assertSuccess(callShellCommand("clear-default-launcher", "--user", "10")); // User-10's launcher should be cleared. assertEquals(null, mService.getUserShortcutsLocked(USER_10).getLastKnownLauncher()); assertEquals(null, mService.getUserShortcutsLocked(USER_10).getCachedLauncher()); // but user'0's shouldn't. assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME), mService.getUserShortcutsLocked(USER_0).getCachedLauncher()); // Change user-0's launcher. prepareGetHomeActivitiesAsUser( /* preferred */ cn(CALLING_PACKAGE_1, "name"), list( ri(CALLING_PACKAGE_1, "name", false, 0) ), USER_0); assertContains( assertSuccess(callShellCommand("get-default-launcher")), "Launcher: ComponentInfo{com.android.test.1/name}"); } public void testUnloadUser() throws Exception { prepareCrossProfileDataSet(); assertNotNull(mService.getShortcutsForTest().get(USER_10)); mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("unload-user", "--user", "10")); assertNull(mService.getShortcutsForTest().get(USER_10)); } public void testClearShortcuts() throws Exception { mRunningUsers.put(USER_10, true); // Add two manifests and two dynamics. addManifestShortcutResource( new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.addDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); }); runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() .selectPinned() .haveIds("ms2", "s2"); }); // First, call for a different package. mRunningUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_2)); // Shouldn't be cleared yet. runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() .selectPinned() .haveIds("ms2", "s2"); }); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_1)); // Only manifest shortcuts will remain, and are no longer pinned. runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2") .areAllEnabled() .areAllNotPinned(); }); } }