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 17 package com.android.server.pm; 18 19 import android.content.Context; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.PackageManager; 22 import android.content.pm.PackageStats; 23 import android.os.SystemClock; 24 import android.os.UserHandle; 25 import android.support.test.InstrumentationRegistry; 26 import android.support.test.runner.AndroidJUnit4; 27 import android.util.Log; 28 29 import com.android.internal.util.ArrayUtils; 30 31 import org.junit.After; 32 import org.junit.Before; 33 import org.junit.Ignore; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 import java.util.Arrays; 38 39 @RunWith(AndroidJUnit4.class) 40 public class InstallerTest { 41 private static final String TAG = "InstallerTest"; 42 43 private Installer mInstaller; 44 45 private final Timer mManual = new Timer("Manual"); 46 private final Timer mQuota = new Timer("Quota"); 47 48 private static class Timer { 49 private final String mTitle; 50 private long mStart; 51 private long mTotal; 52 53 public Timer(String title) { 54 mTitle = title; 55 } 56 57 public void start() { 58 mStart = SystemClock.currentTimeMicro(); 59 } 60 61 public void stop() { 62 mTotal += SystemClock.currentTimeMicro() - mStart; 63 } 64 65 public void reset() { 66 mStart = 0; 67 mTotal = 0; 68 } 69 70 @Override 71 public String toString() { 72 return mTitle + ": " + (mTotal / 1000) + "ms"; 73 } 74 } 75 76 @Before 77 public void setUp() throws Exception { 78 mInstaller = new Installer(getContext()); 79 mInstaller.onStart(); 80 mManual.reset(); 81 mQuota.reset(); 82 } 83 84 @After 85 public void tearDown() throws Exception { 86 Log.i(TAG, mManual.toString()); 87 Log.i(TAG, mQuota.toString()); 88 mInstaller = null; 89 } 90 91 @Test 92 @Ignore("b/68819006") 93 public void testGetAppSize() throws Exception { 94 int[] appIds = null; 95 96 final PackageManager pm = getContext().getPackageManager(); 97 for (ApplicationInfo app : pm.getInstalledApplications(0)) { 98 final int userId = UserHandle.getUserId(app.uid); 99 final int appId = UserHandle.getAppId(app.uid); 100 101 if (ArrayUtils.contains(appIds, appId)) { 102 continue; 103 } else { 104 appIds = ArrayUtils.appendInt(appIds, appId); 105 } 106 107 final String[] packageNames = pm.getPackagesForUid(app.uid); 108 final long[] ceDataInodes = new long[packageNames.length]; 109 final String[] codePaths = new String[packageNames.length]; 110 111 for (int i = 0; i < packageNames.length; i++) { 112 final ApplicationInfo info = pm.getApplicationInfo(packageNames[i], 0); 113 codePaths[i] = info.getCodePath(); 114 } 115 116 final PackageStats stats = new PackageStats(app.packageName); 117 final PackageStats quotaStats = new PackageStats(app.packageName); 118 119 mManual.start(); 120 mInstaller.getAppSize(app.volumeUuid, packageNames, userId, 0, 121 appId, ceDataInodes, codePaths, stats); 122 mManual.stop(); 123 124 mQuota.start(); 125 mInstaller.getAppSize(app.volumeUuid, packageNames, userId, Installer.FLAG_USE_QUOTA, 126 appId, ceDataInodes, codePaths, quotaStats); 127 mQuota.stop(); 128 129 checkEquals(Arrays.toString(packageNames) + " UID=" + app.uid, stats, quotaStats); 130 } 131 } 132 133 @Test 134 @Ignore("b/68819006") 135 public void testGetUserSize() throws Exception { 136 final int[] appIds = getAppIds(UserHandle.USER_SYSTEM); 137 138 final PackageStats stats = new PackageStats("android"); 139 final PackageStats quotaStats = new PackageStats("android"); 140 141 mManual.start(); 142 mInstaller.getUserSize(null, UserHandle.USER_SYSTEM, 0, 143 appIds, stats); 144 mManual.stop(); 145 146 mQuota.start(); 147 mInstaller.getUserSize(null, UserHandle.USER_SYSTEM, Installer.FLAG_USE_QUOTA, 148 appIds, quotaStats); 149 mQuota.stop(); 150 151 checkEquals(Arrays.toString(appIds), stats, quotaStats); 152 } 153 154 @Test 155 @Ignore("b/68819006") 156 public void testGetExternalSize() throws Exception { 157 final int[] appIds = getAppIds(UserHandle.USER_SYSTEM); 158 159 mManual.start(); 160 final long[] stats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM, 0, appIds); 161 mManual.stop(); 162 163 mQuota.start(); 164 final long[] quotaStats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM, 165 Installer.FLAG_USE_QUOTA, appIds); 166 mQuota.stop(); 167 168 for (int i = 0; i < stats.length; i++) { 169 checkEquals("#" + i, stats[i], quotaStats[i]); 170 } 171 } 172 173 private int[] getAppIds(int userId) { 174 int[] appIds = null; 175 for (ApplicationInfo app : getContext().getPackageManager().getInstalledApplicationsAsUser( 176 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)) { 177 final int appId = UserHandle.getAppId(app.uid); 178 if (!ArrayUtils.contains(appIds, appId)) { 179 appIds = ArrayUtils.appendInt(appIds, appId); 180 } 181 } 182 return appIds; 183 } 184 185 private static Context getContext() { 186 return InstrumentationRegistry.getContext(); 187 } 188 189 private static void checkEquals(String msg, PackageStats a, PackageStats b) { 190 checkEquals(msg + " codeSize", a.codeSize, b.codeSize); 191 checkEquals(msg + " dataSize", a.dataSize, b.dataSize); 192 checkEquals(msg + " cacheSize", a.cacheSize, b.cacheSize); 193 checkEquals(msg + " externalCodeSize", a.externalCodeSize, b.externalCodeSize); 194 checkEquals(msg + " externalDataSize", a.externalDataSize, b.externalDataSize); 195 checkEquals(msg + " externalCacheSize", a.externalCacheSize, b.externalCacheSize); 196 } 197 198 private static void checkEquals(String msg, long expected, long actual) { 199 if (expected != actual) { 200 Log.e(TAG, msg + " expected " + expected + " actual " + actual); 201 } 202 } 203 } 204