1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.packageinstaller.admin.cts;
17 
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assume.assumeTrue;
24 
25 import android.app.admin.DevicePolicyManager;
26 import android.content.BroadcastReceiver;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.pm.PackageInstaller;
32 import android.content.pm.ResolveInfo;
33 import android.os.Process;
34 import android.os.UserHandle;
35 import android.os.UserManager;
36 import android.text.TextUtils;
37 
38 import com.android.bedstead.harrier.annotations.RequireRunOnSystemUser;
39 import com.android.bedstead.harrier.BedsteadJUnit4;
40 import com.android.cts.install.lib.Install;
41 import com.android.cts.install.lib.InstallUtils;
42 import com.android.cts.install.lib.TestApp;
43 import com.android.cts.install.lib.Uninstall;
44 
45 import org.junit.After;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 
50 import java.util.concurrent.CountDownLatch;
51 import java.util.concurrent.TimeUnit;
52 
53 /**
54  * This class tests {@link PackageInstaller#ACTION_SESSION_COMMITTED} is properly sent to the
55  * launcher app.
56  */
57 @RunWith(BedsteadJUnit4.class)
58 @RequireRunOnSystemUser
59 public class SessionCommitBroadcastTest extends BasePackageInstallTest {
60 
61     private static final long BROADCAST_TIMEOUT_SECS = 20;
62     private ComponentName mDefaultLauncher;
63     private ComponentName mThisAppLauncher;
64     private SessionCommitReceiver mReceiver;
65 
66     @Before
setUpTest()67     public void setUpTest() throws Exception {
68         mDefaultLauncher = ComponentName.unflattenFromString(getDefaultLauncher());
69         mThisAppLauncher = new ComponentName(mContext, LauncherActivity.class);
70         mReceiver = new SessionCommitReceiver();
71     }
72 
73     @After
tearDownTest()74     public void tearDownTest() throws Exception {
75         mContext.unregisterReceiver(mReceiver);
76         Uninstall.packages(TestApp.A);
77     }
78 
79     @Test
testBroadcastNotReceivedForDifferentLauncher()80     public void testBroadcastNotReceivedForDifferentLauncher() throws Exception {
81         if (mDefaultLauncher.equals(mThisAppLauncher)) {
82             // Find a different launcher
83             Intent homeIntent = new Intent(Intent.ACTION_MAIN)
84                     .addCategory(Intent.CATEGORY_HOME)
85                     .addCategory(Intent.CATEGORY_DEFAULT);
86             for (ResolveInfo info : mPackageManager.queryIntentActivities(homeIntent, 0)) {
87                 mDefaultLauncher =
88                         new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
89                 if (!mDefaultLauncher.equals(mThisAppLauncher)) {
90                     setLauncher(mDefaultLauncher.flattenToString());
91                     break;
92                 }
93             }
94         }
95 
96         assertFalse("No default launcher found", mDefaultLauncher.equals(mThisAppLauncher));
97         // install the app
98         assertInstallPackage();
99         // Broadcast not received
100         assertNull(mReceiver.blockingGetIntent());
101 
102         tryUninstallPackage();
103     }
104 
verifySessionIntent(Intent intent)105     private void verifySessionIntent(Intent intent) {
106         assertNotNull(intent);
107         PackageInstaller.SessionInfo info = intent
108                 .getParcelableExtra(PackageInstaller.EXTRA_SESSION);
109         assertEquals(TEST_APP_PKG, info.getAppPackageName());
110     }
111 
112     @Test
testBroadcastNotReceivedForUpdateInstall()113     public void testBroadcastNotReceivedForUpdateInstall() throws Exception {
114         try {
115             setLauncher(mThisAppLauncher.flattenToString());
116 
117             int sessionId = Install.single(TestApp.A1).commit();
118             assertEquals(1, InstallUtils.getInstalledVersion(TestApp.A));
119             // Check the broadcast is received for a new install and session id matches
120             Intent intent = mReceiver.blockingGetIntent();
121             PackageInstaller.SessionInfo info =
122                     intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
123             assertEquals(sessionId, info.getSessionId());
124 
125             mContext.unregisterReceiver(mReceiver);
126             mReceiver = new SessionCommitReceiver();
127             Install.single(TestApp.A2).commit();
128             assertEquals(2, InstallUtils.getInstalledVersion(TestApp.A));
129 
130             // Check no broadcast is received for an update install
131             intent = mReceiver.blockingGetIntent();
132             assertNull(intent);
133         } finally {
134             // Revert to default launcher
135             setLauncher(mDefaultLauncher.flattenToString());
136         }
137     }
138 
139     @Test
testBroadcastReceivedForNewInstall()140     public void testBroadcastReceivedForNewInstall() throws Exception {
141         setLauncher(mThisAppLauncher.flattenToString());
142 
143         // install the app
144         assertInstallPackage();
145 
146         verifySessionIntent(mReceiver.blockingGetIntent());
147         mContext.unregisterReceiver(mReceiver);
148         forceUninstall();
149         mReceiver = new SessionCommitReceiver();
150         assertInstallPackage();
151         verifySessionIntent(mReceiver.blockingGetIntent());
152 
153         tryUninstallPackage();
154         // Revert to default launcher
155         setLauncher(mDefaultLauncher.flattenToString());
156     }
157 
158     @Test
testBroadcastReceivedForEnablingApp()159     public void testBroadcastReceivedForEnablingApp() throws Exception {
160         assumeTrue("Cannot add multiple users", UserManager.supportsMultipleUsers());
161 
162         setLauncher(mThisAppLauncher.flattenToString());
163 
164         ComponentName cn = new ComponentName(mContext, BasicAdminReceiver.class);
165         UserHandle user = mDevicePolicyManager.createAndManageUser(cn,
166                 "Test User " + System.currentTimeMillis(), cn,
167                 null, DevicePolicyManager.SKIP_SETUP_WIZARD);
168         int userId = user.getIdentifier();
169         assertTrue(TextUtils.join(" ", runShellCommand("am start-user " + userId))
170                 .toLowerCase().contains("success"));
171 
172         // Install app for the second user
173         assertTrue(TextUtils.join(" ", runShellCommand(
174                 "pm install -r --user " + userId + "  " + TEST_APP_LOCATION))
175                 .toLowerCase().contains("success"));
176 
177         // Enable the app for this user
178         runShellCommand("cmd package install-existing --user " +
179                 Process.myUserHandle().getIdentifier() + "  " + TEST_APP_PKG);
180         verifySessionIntent(mReceiver.blockingGetIntent());
181 
182         // Cleanup
183         setLauncher(mDefaultLauncher.flattenToString());
184         mDevicePolicyManager.removeUser(cn, user);
185         forceUninstall();
186     }
187 
getDefaultLauncher()188     private String getDefaultLauncher() throws Exception {
189         final String PREFIX = "Launcher: ComponentInfo{";
190         final String POSTFIX = "}";
191         for (String s : runShellCommand("cmd shortcut get-default-launcher")) {
192             if (s.startsWith(PREFIX) && s.endsWith(POSTFIX)) {
193                 return s.substring(PREFIX.length(), s.length() - POSTFIX.length());
194             }
195         }
196         throw new Exception("Default launcher not found");
197     }
198 
setLauncher(String component)199     private void setLauncher(String component) throws Exception {
200         runShellCommand("cmd package set-home-activity --user "
201                 + mInstrumentation.getContext().getUserId() + " " + component);
202     }
203 
204     private class SessionCommitReceiver extends BroadcastReceiver {
205 
206         private final CountDownLatch mLatch = new CountDownLatch(1);
207         private Intent mIntent;
208 
SessionCommitReceiver()209         SessionCommitReceiver() {
210             mContext.registerReceiver(this,
211                     new IntentFilter(PackageInstaller.ACTION_SESSION_COMMITTED),
212                     Context.RECEIVER_EXPORTED);
213         }
214 
215         @Override
onReceive(Context context, Intent intent)216         public void onReceive(Context context, Intent intent) {
217             assertNull(mIntent);
218             mIntent = intent;
219             mLatch.countDown();
220         }
221 
blockingGetIntent()222         public Intent blockingGetIntent() throws Exception {
223             mLatch.await(BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
224             return mIntent;
225         }
226     }
227 }
228