1c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi/* 2c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * Copyright (C) 2016 The Android Open Source Project 3c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * 4c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * Licensed under the Apache License, Version 2.0 (the "License"); 5c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * you may not use this file except in compliance with the License. 6c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * You may obtain a copy of the License at 7c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * 8c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * http://www.apache.org/licenses/LICENSE-2.0 9c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * 10c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * Unless required by applicable law or agreed to in writing, software 11c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * distributed under the License is distributed on an "AS IS" BASIS, 12c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * See the License for the specific language governing permissions and 14c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi * limitations under the License. 15c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi */ 16c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 17c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishipackage com.android.server.storage; 18c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 19d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishiimport android.app.usage.StorageStats; 20d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishiimport android.app.usage.StorageStatsManager; 21c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.content.pm.UserInfo; 22c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.content.Context; 23c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.content.pm.ApplicationInfo; 24c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.content.pm.IPackageStatsObserver; 25c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.content.pm.PackageManager; 26c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.content.pm.PackageStats; 27d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishiimport android.os.UserHandle; 28c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.os.UserManager; 29c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.os.storage.VolumeInfo; 30c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport android.test.AndroidTestCase; 31579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishiimport android.util.ArrayMap; 32579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishiimport android.util.Log; 33579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi 34c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.junit.Before; 35c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.junit.Test; 36c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.junit.runner.RunWith; 37c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.junit.runners.JUnit4; 38c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.mockito.Mock; 39c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.mockito.Mockito; 40c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.mockito.MockitoAnnotations; 41c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.mockito.invocation.InvocationOnMock; 42c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport org.mockito.stubbing.Answer; 43c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 44c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport java.util.ArrayList; 45c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport java.util.List; 46579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishiimport java.util.Map; 47c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport java.util.concurrent.CountDownLatch; 48c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport java.util.concurrent.TimeUnit; 49c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 50c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport static com.google.common.truth.Truth.assertThat; 51c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport static org.mockito.Matchers.any; 52c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport static org.mockito.Matchers.anyInt; 53579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishiimport static org.mockito.Matchers.anyString; 54c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport static org.mockito.Matchers.eq; 55c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport static org.mockito.Mockito.doAnswer; 56c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishiimport static org.mockito.Mockito.when; 57c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 58c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi@RunWith(JUnit4.class) 59c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishipublic class AppCollectorTest extends AndroidTestCase { 60c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi private static final long TIMEOUT = TimeUnit.MINUTES.toMillis(1); 61c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Mock private Context mContext; 62c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Mock private PackageManager mPm; 63c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Mock private UserManager mUm; 64d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi @Mock private StorageStatsManager mSsm; 65c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi private List<UserInfo> mUsers; 66579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi private Map<Integer, List<ApplicationInfo>> mUserApps; 67c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 68c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Before 69c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi public void setUp() throws Exception { 70c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi super.setUp(); 71c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi MockitoAnnotations.initMocks(this); 72c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi when(mContext.getPackageManager()).thenReturn(mPm); 73c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUm); 74d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi when(mContext.getSystemService(Context.STORAGE_STATS_SERVICE)).thenReturn(mSsm); 75c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 76c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi // Set up the app list. 77579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi doAnswer((InvocationOnMock invocation) -> { 78579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi Integer userId = (Integer) invocation.getArguments()[1]; 79579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi return mUserApps.get(userId); 80579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi }).when(mPm).getInstalledApplicationsAsUser(anyInt(), anyInt()); 81c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 82c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi // Set up the user list with a single user (0). 83c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi mUsers = new ArrayList<>(); 84c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi mUsers.add(new UserInfo(0, "", 0)); 85579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi 86579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi mUserApps = new ArrayMap<>(); 87579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi mUserApps.put(0, new ArrayList<>()); 88c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi when(mUm.getUsers()).thenReturn(mUsers); 89c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi } 90c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 91c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Test 92c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi public void testNoApps() throws Exception { 93c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 94c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi volume.fsUuid = "testuuid"; 95c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi AppCollector collector = new AppCollector(mContext, volume); 96c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 97c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi assertThat(collector.getPackageStats(TIMEOUT)).isEmpty(); 98c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi } 99c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 100c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Test 101c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi public void testAppOnExternalVolume() throws Exception { 102579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi addApplication("com.test.app", "differentuuid", 0); 103c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 104c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi volume.fsUuid = "testuuid"; 105c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi AppCollector collector = new AppCollector(mContext, volume); 106c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 107c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi assertThat(collector.getPackageStats(TIMEOUT)).isEmpty(); 108c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi } 109c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 110c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Test 111c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi public void testOneValidApp() throws Exception { 112579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi addApplication("com.test.app", "testuuid", 0); 113c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 114c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi volume.fsUuid = "testuuid"; 115c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi AppCollector collector = new AppCollector(mContext, volume); 116c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi PackageStats stats = new PackageStats("com.test.app"); 117c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 118d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi when(mSsm.queryStatsForPackage(eq("testuuid"), 119d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats()); 120d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats); 121c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi } 122c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 123c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi @Test 124c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi public void testMultipleUsersOneApp() throws Exception { 125579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi addApplication("com.test.app", "testuuid", 0); 126579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi mUserApps.put(1, new ArrayList<>()); 127579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi addApplication("com.test.app", "testuuid", 1); 128c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi mUsers.add(new UserInfo(1, "", 0)); 129c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 130c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 131c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi volume.fsUuid = "testuuid"; 132c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi AppCollector collector = new AppCollector(mContext, volume); 133c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi PackageStats stats = new PackageStats("com.test.app"); 134c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi PackageStats otherStats = new PackageStats("com.test.app"); 135c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi otherStats.userHandle = 1; 136c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 137d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi when(mSsm.queryStatsForPackage(eq("testuuid"), 138d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats()); 139d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi when(mSsm.queryStatsForPackage(eq("testuuid"), 140d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi eq("com.test.app"), eq(UserHandle.of(1)))).thenReturn(new StorageStats()); 141d7b0329ab7c3355c84f8227939e88f305dd78b51Daniel Nishi assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats, otherStats); 142c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi } 143c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi 144d54f3a487bba1dc5008e2e1482ef451a59500752Daniel Nishi @Test(expected=NullPointerException.class) 145d54f3a487bba1dc5008e2e1482ef451a59500752Daniel Nishi public void testNullVolumeShouldCauseNPE() throws Exception { 146d54f3a487bba1dc5008e2e1482ef451a59500752Daniel Nishi AppCollector collector = new AppCollector(mContext, null); 147d54f3a487bba1dc5008e2e1482ef451a59500752Daniel Nishi } 148d54f3a487bba1dc5008e2e1482ef451a59500752Daniel Nishi 149579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi @Test 150579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi public void testAppNotFoundDoesntCauseCrash() throws Exception { 151579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi VolumeInfo volume = new VolumeInfo("testuuid", 0, null, null); 152579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi addApplication("com.test.app", "uuid", 0); 153579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi mUsers.add(new UserInfo(1, "", 0)); 154579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi mUserApps.put(1, new ArrayList<>()); 155579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi AppCollector collector = new AppCollector(mContext, volume); 156579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi when(mSsm.queryStatsForPackage(anyString(), anyString(), any(UserHandle.class))).thenThrow( 157579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi new IllegalStateException()); 158579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi 159579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi assertThat(collector.getPackageStats(TIMEOUT)).isEmpty(); 160579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi } 161579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi 162579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi private void addApplication(String packageName, String uuid, int userId) { 163c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi ApplicationInfo info = new ApplicationInfo(); 164c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi info.packageName = packageName; 165c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi info.volumeUuid = uuid; 166579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi List<ApplicationInfo> userApps = mUserApps.get(userId); 167579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi if (userApps == null) { 168579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi userApps = new ArrayList<>(); 169579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi mUserApps.put(userId, userApps); 170579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi } 171579e5581d5339dbdc79b9176fcc2fad660d155dbDaniel Nishi userApps.add(info); 172c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi } 173c7d9de59bfa083472a5c8fcfc02c2363b33e204fDaniel Nishi} 174