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 */
16package com.android.server.pm;
17
18import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertContains;
19import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
20import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertSuccess;
21import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
22import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
23import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.readAll;
24import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resultContains;
25
26import android.content.ComponentName;
27import android.os.Bundle;
28import android.os.ParcelFileDescriptor;
29import android.os.Process;
30import android.os.RemoteException;
31import android.os.ResultReceiver;
32import android.test.suitebuilder.annotation.SmallTest;
33
34import com.android.frameworks.servicestests.R;
35import com.android.server.pm.ShortcutService.ConfigConstants;
36
37import java.io.File;
38import java.io.IOException;
39import java.util.List;
40import java.util.concurrent.atomic.AtomicInteger;
41
42/**
43 * Unit test for "cmd shortcut"
44 *
45 * Launcher related commands are tested in
46 */
47@SmallTest
48public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
49    private List<String> callShellCommand(String... args) throws IOException, RemoteException {
50
51        // For reset to work, the current time needs to be incrementing.
52        mInjectedCurrentTimeMillis++;
53
54        final AtomicInteger resultCode = new AtomicInteger(Integer.MIN_VALUE);
55
56        final ResultReceiver rr = new ResultReceiver(mHandler) {
57            @Override
58            public void send(int resultCode_, Bundle resultData) {
59                resultCode.set(resultCode_);
60            }
61        };
62        final File out = File.createTempFile("shellout-", ".tmp",
63                getTestContext().getCacheDir());
64        try {
65            try (final ParcelFileDescriptor fd = ParcelFileDescriptor.open(out,
66                    ParcelFileDescriptor.MODE_READ_WRITE)) {
67                mService.onShellCommand(
68                    /* fdin*/ null,
69                    /* fdout*/ fd.getFileDescriptor(),
70                    /* fderr*/ fd.getFileDescriptor(),
71                        args, null, rr);
72            }
73            return readAll(out);
74        } finally {
75            out.delete();
76        }
77    }
78
79    public void testNonShell() throws Exception {
80        mService.mMaxUpdatesPerInterval = 99;
81
82        mInjectedCallingUid = 12345;
83        assertExpectException(SecurityException.class, "must be shell",
84                () -> callShellCommand("reset-config"));
85
86        mInjectedCallingUid = Process.SYSTEM_UID;
87        assertExpectException(SecurityException.class, "must be shell",
88                () -> callShellCommand("reset-config"));
89
90        assertEquals(99, mService.mMaxUpdatesPerInterval);
91    }
92
93    public void testRoot() throws Exception {
94        mService.mMaxUpdatesPerInterval = 99;
95
96        mInjectedCallingUid = Process.ROOT_UID;
97        assertSuccess(callShellCommand("reset-config"));
98
99        assertEquals(3, mService.mMaxUpdatesPerInterval);
100    }
101
102    public void testRestConfig() throws Exception {
103        mService.mMaxUpdatesPerInterval = 99;
104
105        mInjectedCallingUid = Process.SHELL_UID;
106        assertSuccess(callShellCommand("reset-config"));
107
108        assertEquals(3, mService.mMaxUpdatesPerInterval);
109    }
110
111    public void testOverrideConfig() throws Exception {
112        mService.mMaxUpdatesPerInterval = 99;
113
114        mInjectedCallingUid = Process.SHELL_UID;
115        assertSuccess(callShellCommand("override-config",
116                ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=1"));
117
118        assertEquals(1, mService.mMaxUpdatesPerInterval);
119    }
120
121    public void testResetThrottling() throws Exception {
122        prepareCrossProfileDataSet();
123
124        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
125            assertTrue(mManager.getRemainingCallCount() < 3);
126        });
127        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
128            assertTrue(mManager.getRemainingCallCount() < 3);
129        });
130
131        mInjectedCallingUid = Process.SHELL_UID;
132        assertSuccess(callShellCommand("reset-throttling"));
133
134        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
135            assertEquals(3, mManager.getRemainingCallCount());
136        });
137        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
138            assertTrue(mManager.getRemainingCallCount() < 3);
139        });
140    }
141
142    public void testResetThrottling_user_not_running() throws Exception {
143        prepareCrossProfileDataSet();
144
145        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
146            assertTrue(mManager.getRemainingCallCount() < 3);
147        });
148        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
149            assertTrue(mManager.getRemainingCallCount() < 3);
150        });
151
152        mInjectedCallingUid = Process.SHELL_UID;
153
154        mRunningUsers.put(USER_10, false);
155
156        assertTrue(resultContains(
157                callShellCommand("reset-throttling", "--user", "10"),
158                "User 10 is not running or locked"));
159
160        mRunningUsers.put(USER_10, true);
161
162        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
163            assertTrue(mManager.getRemainingCallCount() < 3);
164        });
165        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
166            assertTrue(mManager.getRemainingCallCount() < 3);
167        });
168    }
169
170    public void testResetThrottling_user_running() throws Exception {
171        prepareCrossProfileDataSet();
172
173        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
174            assertTrue(mManager.getRemainingCallCount() < 3);
175        });
176        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
177            assertTrue(mManager.getRemainingCallCount() < 3);
178        });
179
180        mRunningUsers.put(USER_10, true);
181        mUnlockedUsers.put(USER_10, true);
182
183        mInjectedCallingUid = Process.SHELL_UID;
184        assertSuccess(callShellCommand("reset-throttling", "--user", "10"));
185
186        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
187            assertTrue(mManager.getRemainingCallCount() < 3);
188        });
189        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
190            assertEquals(3, mManager.getRemainingCallCount());
191        });
192    }
193
194    public void testResetAllThrottling() throws Exception {
195        prepareCrossProfileDataSet();
196
197        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
198            assertTrue(mManager.getRemainingCallCount() < 3);
199        });
200        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
201            assertTrue(mManager.getRemainingCallCount() < 3);
202        });
203
204        mInjectedCallingUid = Process.SHELL_UID;
205        assertSuccess(callShellCommand("reset-all-throttling"));
206
207        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
208            assertEquals(3, mManager.getRemainingCallCount());
209        });
210        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
211            assertEquals(3, mManager.getRemainingCallCount());
212        });
213    }
214
215    public void testLauncherCommands() throws Exception {
216        prepareGetHomeActivitiesAsUser(
217                /* preferred */ null,
218                list(getSystemLauncher(), getFallbackLauncher()),
219                USER_0);
220
221        prepareGetHomeActivitiesAsUser(
222                /* preferred */ cn(CALLING_PACKAGE_2, "name"),
223                list(getSystemLauncher(), getFallbackLauncher(),
224                        ri(CALLING_PACKAGE_1, "name", false, 0),
225                        ri(CALLING_PACKAGE_2, "name", false, 0)
226                ),
227                USER_10);
228
229        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
230
231        // First, test "get".
232
233        mRunningUsers.put(USER_10, true);
234        mUnlockedUsers.put(USER_10, true);
235        mInjectedCallingUid = Process.SHELL_UID;
236        assertContains(
237                assertSuccess(callShellCommand("get-default-launcher")),
238                "Launcher: ComponentInfo{com.android.systemlauncher/systemlauncher_name}");
239
240        assertContains(
241                assertSuccess(callShellCommand("get-default-launcher", "--user", "10")),
242                "Launcher: ComponentInfo{com.android.test.2/name}");
243
244        // Next, test "clear".
245        assertSuccess(callShellCommand("clear-default-launcher", "--user", "10"));
246
247        // User-10's launcher should be cleared.
248        assertEquals(null, mService.getUserShortcutsLocked(USER_10).getLastKnownLauncher());
249        assertEquals(null, mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
250
251        // but user'0's shouldn't.
252        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
253                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
254
255        // Change user-0's launcher.
256        prepareGetHomeActivitiesAsUser(
257                /* preferred */ cn(CALLING_PACKAGE_1, "name"),
258                list(
259                        ri(CALLING_PACKAGE_1, "name", false, 0)
260                ),
261                USER_0);
262        assertContains(
263                assertSuccess(callShellCommand("get-default-launcher")),
264                "Launcher: ComponentInfo{com.android.test.1/name}");
265    }
266
267    public void testUnloadUser() throws Exception {
268        prepareCrossProfileDataSet();
269
270        assertNotNull(mService.getShortcutsForTest().get(USER_10));
271
272        mRunningUsers.put(USER_10, true);
273        mUnlockedUsers.put(USER_10, true);
274
275        mInjectedCallingUid = Process.SHELL_UID;
276        assertSuccess(callShellCommand("unload-user", "--user", "10"));
277
278        assertNull(mService.getShortcutsForTest().get(USER_10));
279    }
280
281    public void testClearShortcuts() throws Exception {
282
283        mRunningUsers.put(USER_10, true);
284
285        // Add two manifests and two dynamics.
286        addManifestShortcutResource(
287                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
288                R.xml.shortcut_2);
289        updatePackageVersion(CALLING_PACKAGE_1, 1);
290        mService.mPackageMonitor.onReceive(getTestContext(),
291                genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
292
293        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
294            assertTrue(mManager.addDynamicShortcuts(list(
295                    makeShortcut("s1"), makeShortcut("s2"))));
296        });
297        runWithCaller(LAUNCHER_1, USER_10, () -> {
298            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10);
299        });
300
301        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
302            assertWith(getCallerShortcuts())
303                    .haveIds("ms1", "ms2", "s1", "s2")
304                    .areAllEnabled()
305
306                    .selectPinned()
307                    .haveIds("ms2", "s2");
308        });
309
310        // First, call for a different package.
311
312        mRunningUsers.put(USER_10, true);
313        mUnlockedUsers.put(USER_10, true);
314
315        mInjectedCallingUid = Process.SHELL_UID;
316        assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_2));
317
318        // Shouldn't be cleared yet.
319        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
320            assertWith(getCallerShortcuts())
321                    .haveIds("ms1", "ms2", "s1", "s2")
322                    .areAllEnabled()
323
324                    .selectPinned()
325                    .haveIds("ms2", "s2");
326        });
327
328        mInjectedCallingUid = Process.SHELL_UID;
329        assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_1));
330
331        // Only manifest shortcuts will remain, and are no longer pinned.
332        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
333            assertWith(getCallerShortcuts())
334                    .haveIds("ms1", "ms2")
335                    .areAllEnabled()
336                    .areAllNotPinned();
337        });
338    }
339}
340