/* * 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; mRunningUsers.put(USER_10, false); assertTrue(resultContains( callShellCommand("reset-throttling", "--user", "10"), "User 10 is not running or locked")); mRunningUsers.put(USER_10, true); 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(); }); } }