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 */ 16 17 package com.android.server.storage; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Matchers.any; 22 import static org.mockito.Matchers.anyInt; 23 import static org.mockito.Matchers.anyLong; 24 import static org.mockito.Matchers.anyString; 25 import static org.mockito.Matchers.isNull; 26 import static org.mockito.Mockito.doReturn; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.spy; 29 import static org.mockito.Mockito.when; 30 31 import android.app.job.JobService; 32 import android.app.job.JobServiceEngine; 33 import android.app.usage.ExternalStorageStats; 34 import android.app.usage.StorageStatsManager; 35 import android.content.Context; 36 import android.content.pm.PackageManager; 37 import android.content.pm.PackageStats; 38 import android.os.BatteryManager; 39 import android.os.UserHandle; 40 import android.os.UserManager; 41 import android.os.storage.StorageManager; 42 import android.os.storage.VolumeInfo; 43 import android.provider.Settings; 44 import android.test.AndroidTestCase; 45 import android.test.mock.MockContentResolver; 46 47 import com.android.internal.util.test.FakeSettingsProvider; 48 import com.android.server.storage.DiskStatsLoggingService.LogRunnable; 49 50 import libcore.io.IoUtils; 51 52 import org.json.JSONObject; 53 import org.junit.Before; 54 import org.junit.Rule; 55 import org.junit.Test; 56 import org.junit.rules.TemporaryFolder; 57 import org.junit.runner.RunWith; 58 import org.junit.runners.JUnit4; 59 import org.mockito.Mock; 60 import org.mockito.MockitoAnnotations; 61 62 import java.io.File; 63 import java.io.PrintStream; 64 import java.lang.reflect.Field; 65 import java.util.ArrayList; 66 67 @RunWith(JUnit4.class) 68 public class DiskStatsLoggingServiceTest extends AndroidTestCase { 69 @Rule public TemporaryFolder mTemporaryFolder; 70 @Rule public TemporaryFolder mDownloads; 71 @Mock private AppCollector mCollector; 72 @Mock private JobService mJobService; 73 @Mock private StorageStatsManager mSsm; 74 private ExternalStorageStats mStorageStats; 75 private File mInputFile; 76 77 78 @Before 79 public void setUp() throws Exception { 80 super.setUp(); 81 MockitoAnnotations.initMocks(this); 82 mTemporaryFolder = new TemporaryFolder(); 83 mTemporaryFolder.create(); 84 mInputFile = mTemporaryFolder.newFile(); 85 mDownloads = new TemporaryFolder(); 86 mDownloads.create(); 87 mStorageStats = new ExternalStorageStats(); 88 when(mSsm.queryExternalStatsForUser(isNull(String.class), any(UserHandle.class))) 89 .thenReturn(mStorageStats); 90 when(mJobService.getSystemService(anyString())).thenReturn(mSsm); 91 } 92 93 @Test 94 public void testEmptyLog() throws Exception { 95 LogRunnable task = new LogRunnable(); 96 task.setAppCollector(mCollector); 97 task.setDownloadsDirectory(mDownloads.getRoot()); 98 task.setLogOutputFile(mInputFile); 99 task.setSystemSize(0L); 100 task.setContext(mJobService); 101 task.run(); 102 103 JSONObject json = getJsonOutput(); 104 assertThat(json.getLong(DiskStatsFileLogger.PHOTOS_KEY)).isEqualTo(0L); 105 assertThat(json.getLong(DiskStatsFileLogger.VIDEOS_KEY)).isEqualTo(0L); 106 assertThat(json.getLong(DiskStatsFileLogger.AUDIO_KEY)).isEqualTo(0L); 107 assertThat(json.getLong(DiskStatsFileLogger.DOWNLOADS_KEY)).isEqualTo(0L); 108 assertThat(json.getLong(DiskStatsFileLogger.SYSTEM_KEY)).isEqualTo(0L); 109 assertThat(json.getLong(DiskStatsFileLogger.MISC_KEY)).isEqualTo(0L); 110 assertThat(json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY)).isEqualTo(0L); 111 assertThat(json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY)).isEqualTo(0L); 112 assertThat( 113 json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY).length()).isEqualTo(0L); 114 assertThat(json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY).length()).isEqualTo(0L); 115 assertThat(json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY).length()).isEqualTo(0L); 116 } 117 118 @Test 119 public void testPopulatedLogTask() throws Exception { 120 // Write data to directories. 121 writeDataToFile(mDownloads.newFile(), "lol"); 122 mStorageStats.audioBytes = 6L; 123 mStorageStats.imageBytes = 4L; 124 mStorageStats.videoBytes = 5L; 125 mStorageStats.totalBytes = 22L; 126 127 // Write apps. 128 ArrayList<PackageStats> apps = new ArrayList<>(); 129 PackageStats testApp = new PackageStats("com.test.app"); 130 testApp.dataSize = 5L; 131 testApp.cacheSize = 55L; 132 testApp.codeSize = 10L; 133 testApp.userHandle = UserHandle.USER_SYSTEM; 134 apps.add(testApp); 135 when(mCollector.getPackageStats(anyLong())).thenReturn(apps); 136 137 LogRunnable task = new LogRunnable(); 138 task.setAppCollector(mCollector); 139 task.setDownloadsDirectory(mDownloads.getRoot()); 140 task.setLogOutputFile(mInputFile); 141 task.setSystemSize(10L); 142 task.setContext(mJobService); 143 task.run(); 144 145 JSONObject json = getJsonOutput(); 146 assertThat(json.getLong(DiskStatsFileLogger.PHOTOS_KEY)).isEqualTo(4L); 147 assertThat(json.getLong(DiskStatsFileLogger.VIDEOS_KEY)).isEqualTo(5L); 148 assertThat(json.getLong(DiskStatsFileLogger.AUDIO_KEY)).isEqualTo(6L); 149 assertThat(json.getLong(DiskStatsFileLogger.DOWNLOADS_KEY)).isEqualTo(3L); 150 assertThat(json.getLong(DiskStatsFileLogger.SYSTEM_KEY)).isEqualTo(10L); 151 assertThat(json.getLong(DiskStatsFileLogger.MISC_KEY)).isEqualTo(7L); 152 assertThat(json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY)).isEqualTo(10L); 153 assertThat(json.getLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY)).isEqualTo(5L); 154 assertThat(json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY)).isEqualTo(55L); 155 assertThat( 156 json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY).length()).isEqualTo(1L); 157 assertThat(json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY).length()).isEqualTo(1L); 158 assertThat(json.getJSONArray(DiskStatsFileLogger.APP_DATA_KEY).length()).isEqualTo(1L); 159 assertThat(json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY).length()).isEqualTo(1L); 160 } 161 162 @Test 163 public void testDontCrashOnPackageStatsTimeout() throws Exception { 164 when(mCollector.getPackageStats(anyInt())).thenReturn(null); 165 166 LogRunnable task = new LogRunnable(); 167 task.setAppCollector(mCollector); 168 task.setDownloadsDirectory(mDownloads.getRoot()); 169 task.setLogOutputFile(mInputFile); 170 task.setSystemSize(10L); 171 task.setContext(mJobService); 172 task.run(); 173 174 // No exception should be thrown. 175 } 176 177 @Test 178 public void testDontCrashOnRun() throws Exception { 179 DiskStatsLoggingService service = spy(new DiskStatsLoggingService()); 180 BatteryManager batteryManager = mock(BatteryManager.class); 181 when(batteryManager.isCharging()).thenReturn(true); 182 doReturn(batteryManager).when(service).getSystemService(Context.BATTERY_SERVICE); 183 UserManager userManager = mock(UserManager.class); 184 when(userManager.getUsers()).thenReturn(new ArrayList<>()); 185 doReturn(userManager).when(service).getSystemService(Context.USER_SERVICE); 186 doReturn(mSsm).when(service).getSystemService(Context.STORAGE_STATS_SERVICE); 187 doReturn(mock(StorageManager.class)) 188 .when(service) 189 .getSystemService(Context.STORAGE_SERVICE); 190 191 MockContentResolver cr = new MockContentResolver(); 192 cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); 193 doReturn(cr).when(service).getContentResolver(); 194 195 PackageManager pm = mock(PackageManager.class); 196 VolumeInfo volumeInfo = 197 new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL, VolumeInfo.TYPE_PRIVATE, null, null); 198 when(pm.getPrimaryStorageCurrentVolume()).thenReturn(volumeInfo); 199 doReturn(pm).when(service).getPackageManager(); 200 201 doReturn(0).when(service).getUserId(); 202 203 // UGGGGGHHHHHHH! jobFinished is a final method on JobService which crashes when called if 204 // the JobService isn't initialized for real. ServiceTestCase doesn't let us initialize a 205 // service which is built into the framework without crashing, though, so we can't make a 206 // real initialized service. 207 // 208 // And so, we use reflection to set the JobServiceEngine, which is used by the final method, 209 // to be something which won't crash when called. 210 final Field field = JobService.class.getDeclaredField("mEngine"); 211 field.setAccessible(true); 212 field.set(service, mock(JobServiceEngine.class)); 213 214 // Note: This won't clobber your on-device cache file because, technically, 215 // FrameworkServicesTests don't have write permission to actually overwrite the cache file. 216 // We log and fail on the write silently in this case. 217 service.onStartJob(null); 218 } 219 220 private void writeDataToFile(File f, String data) throws Exception{ 221 PrintStream out = new PrintStream(f); 222 out.print(data); 223 out.close(); 224 } 225 226 private JSONObject getJsonOutput() throws Exception { 227 return new JSONObject(IoUtils.readFileAsString(mInputFile.getAbsolutePath())); 228 } 229 } 230