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