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