1 /*
2  * Copyright (C) 2022 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.art;
18 
19 import static org.mockito.Mockito.any;
20 import static org.mockito.Mockito.anyBoolean;
21 import static org.mockito.Mockito.argThat;
22 import static org.mockito.Mockito.eq;
23 import static org.mockito.Mockito.lenient;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.same;
26 
27 import android.os.CancellationSignal;
28 import android.os.SystemProperties;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.os.storage.StorageManager;
32 
33 import com.android.modules.utils.pm.PackageStateModulesUtils;
34 import com.android.server.art.model.Config;
35 import com.android.server.art.testing.StaticMockitoRule;
36 import com.android.server.pm.pkg.AndroidPackage;
37 import com.android.server.pm.pkg.AndroidPackageSplit;
38 import com.android.server.pm.pkg.PackageState;
39 import com.android.server.pm.pkg.PackageUserState;
40 
41 import dalvik.system.PathClassLoader;
42 
43 import org.junit.Before;
44 import org.junit.Rule;
45 import org.mockito.Mock;
46 
47 import java.util.ArrayList;
48 import java.util.List;
49 
50 public class PrimaryDexopterTestBase {
51     protected static final String PKG_NAME = "com.example.foo";
52     protected static final int UID = 12345;
53     protected static final int SHARED_GID = UserHandle.getSharedAppGid(UID);
54     protected static final long ART_VERSION = 331413030l;
55     protected static final String APP_VERSION_NAME = "12.34.56";
56     protected static final long APP_VERSION_CODE = 1536036288l;
57 
58     @Rule
59     public StaticMockitoRule mockitoRule = new StaticMockitoRule(
60             SystemProperties.class, Constants.class, PackageStateModulesUtils.class);
61 
62     @Mock protected PrimaryDexopter.Injector mInjector;
63     @Mock protected IArtd mArtd;
64     @Mock protected UserManager mUserManager;
65     @Mock protected DexUseManagerLocal mDexUseManager;
66     @Mock protected StorageManager mStorageManager;
67     @Mock protected DexMetadataHelper.Injector mDexMetadataHelperInjector;
68     protected PackageState mPkgState;
69     protected AndroidPackage mPkg;
70     protected PackageUserState mPkgUserStateNotInstalled;
71     protected PackageUserState mPkgUserStateInstalled;
72     protected CancellationSignal mCancellationSignal;
73     protected Config mConfig;
74     protected DexMetadataHelper mDexMetadataHelper;
75 
76     @Before
setUp()77     public void setUp() throws Exception {
78         mPkgUserStateNotInstalled = createPackageUserState(false /* installed */);
79         mPkgUserStateInstalled = createPackageUserState(true /* installed */);
80         mPkgState = createPackageState();
81         mPkg = mPkgState.getAndroidPackage();
82         mCancellationSignal = new CancellationSignal();
83         mConfig = new Config();
84         mDexMetadataHelper = new DexMetadataHelper(mDexMetadataHelperInjector);
85 
86         lenient().when(mInjector.getArtd()).thenReturn(mArtd);
87         lenient().when(mInjector.isSystemUiPackage(any())).thenReturn(false);
88         lenient().when(mInjector.isLauncherPackage(any())).thenReturn(false);
89         lenient().when(mInjector.getUserManager()).thenReturn(mUserManager);
90         lenient().when(mInjector.getDexUseManager()).thenReturn(mDexUseManager);
91         lenient().when(mInjector.getStorageManager()).thenReturn(mStorageManager);
92         lenient().when(mInjector.getArtVersion()).thenReturn(ART_VERSION);
93         lenient().when(mInjector.getConfig()).thenReturn(mConfig);
94         lenient().when(mInjector.getDexMetadataHelper()).thenReturn(mDexMetadataHelper);
95         lenient().when(mInjector.isPreReboot()).thenReturn(false);
96 
97         lenient()
98                 .when(SystemProperties.get("dalvik.vm.systemuicompilerfilter"))
99                 .thenReturn("speed");
100         lenient()
101                 .when(SystemProperties.getBoolean(eq("dalvik.vm.always_debuggable"), anyBoolean()))
102                 .thenReturn(false);
103         lenient().when(SystemProperties.get("dalvik.vm.appimageformat")).thenReturn("lz4");
104         lenient().when(SystemProperties.get("pm.dexopt.shared")).thenReturn("speed");
105 
106         // No ISA translation.
107         lenient()
108                 .when(SystemProperties.get(argThat(arg -> arg.startsWith("ro.dalvik.vm.isa."))))
109                 .thenReturn("");
110 
111         lenient().when(Constants.getPreferredAbi()).thenReturn("arm64-v8a");
112         lenient().when(Constants.getNative64BitAbi()).thenReturn("arm64-v8a");
113         lenient().when(Constants.getNative32BitAbi()).thenReturn("armeabi-v7a");
114 
115         lenient()
116                 .when(mUserManager.getUserHandles(anyBoolean()))
117                 .thenReturn(List.of(UserHandle.of(0), UserHandle.of(1), UserHandle.of(2)));
118 
119         lenient().when(mDexUseManager.isPrimaryDexUsedByOtherApps(any(), any())).thenReturn(false);
120 
121         lenient().when(mStorageManager.getAllocatableBytes(any())).thenReturn(1l);
122     }
123 
createPackage()124     private AndroidPackage createPackage() {
125         // This package has the base APK and one split APK that has code.
126         AndroidPackage pkg = mock(AndroidPackage.class);
127         var baseSplit = mock(AndroidPackageSplit.class);
128         lenient().when(baseSplit.getPath()).thenReturn("/somewhere/app/foo/base.apk");
129         lenient().when(baseSplit.isHasCode()).thenReturn(true);
130         lenient().when(baseSplit.getClassLoaderName()).thenReturn(PathClassLoader.class.getName());
131 
132         var split0 = mock(AndroidPackageSplit.class);
133         lenient().when(split0.getName()).thenReturn("split_0");
134         lenient().when(split0.getPath()).thenReturn("/somewhere/app/foo/split_0.apk");
135         lenient().when(split0.isHasCode()).thenReturn(true);
136 
137         var split1 = mock(AndroidPackageSplit.class);
138         lenient().when(split1.getName()).thenReturn("split_1");
139         lenient().when(split1.getPath()).thenReturn("/somewhere/app/foo/split_1.apk");
140         lenient().when(split1.isHasCode()).thenReturn(false);
141 
142         var splits = List.of(baseSplit, split0, split1);
143         lenient().when(pkg.getSplits()).thenReturn(splits);
144 
145         lenient().when(pkg.isVmSafeMode()).thenReturn(false);
146         lenient().when(pkg.isDebuggable()).thenReturn(false);
147         lenient().when(pkg.getTargetSdkVersion()).thenReturn(123);
148         lenient().when(pkg.isSignedWithPlatformKey()).thenReturn(false);
149         lenient().when(pkg.isNonSdkApiRequested()).thenReturn(false);
150         lenient().when(pkg.getVersionName()).thenReturn(APP_VERSION_NAME);
151         lenient().when(pkg.getLongVersionCode()).thenReturn(APP_VERSION_CODE);
152         return pkg;
153     }
154 
createPackageState()155     private PackageState createPackageState() {
156         PackageState pkgState = mock(PackageState.class);
157         lenient().when(pkgState.getPackageName()).thenReturn(PKG_NAME);
158         lenient().when(pkgState.getPrimaryCpuAbi()).thenReturn("arm64-v8a");
159         lenient().when(pkgState.getSecondaryCpuAbi()).thenReturn("armeabi-v7a");
160         lenient().when(pkgState.getAppId()).thenReturn(UID);
161         lenient().when(pkgState.getSharedLibraryDependencies()).thenReturn(new ArrayList<>());
162         lenient().when(pkgState.getStateForUser(any())).thenReturn(mPkgUserStateNotInstalled);
163         AndroidPackage pkg = createPackage();
164         lenient().when(pkgState.getAndroidPackage()).thenReturn(pkg);
165         lenient()
166                 .when(PackageStateModulesUtils.isLoadableInOtherProcesses(
167                         same(pkgState), anyBoolean()))
168                 .thenReturn(false);
169         return pkgState;
170     }
171 
createPackageUserState(boolean isInstalled)172     private PackageUserState createPackageUserState(boolean isInstalled) {
173         PackageUserState pkgUserState = mock(PackageUserState.class);
174         lenient().when(pkgUserState.isInstalled()).thenReturn(isInstalled);
175         return pkgUserState;
176     }
177 
dexoptIsNotNeeded()178     protected GetDexoptNeededResult dexoptIsNotNeeded() {
179         return dexoptIsNotNeeded(true /* hasDexCode */);
180     }
181 
dexoptIsNotNeeded(boolean hasDexCode)182     protected GetDexoptNeededResult dexoptIsNotNeeded(boolean hasDexCode) {
183         var result = new GetDexoptNeededResult();
184         result.isDexoptNeeded = false;
185         result.hasDexCode = hasDexCode;
186         return result;
187     }
188 
dexoptIsNeeded()189     protected GetDexoptNeededResult dexoptIsNeeded() {
190         return dexoptIsNeeded(ArtifactsLocation.NONE_OR_ERROR);
191     }
192 
dexoptIsNeeded(@rtifactsLocation int location)193     protected GetDexoptNeededResult dexoptIsNeeded(@ArtifactsLocation int location) {
194         var result = new GetDexoptNeededResult();
195         result.isDexoptNeeded = true;
196         result.artifactsLocation = location;
197         if (location != ArtifactsLocation.NONE_OR_ERROR) {
198             result.isVdexUsable = true;
199         }
200         result.hasDexCode = true;
201         return result;
202     }
203 
createArtdDexoptResult(boolean cancelled, long wallTimeMs, long cpuTimeMs, long sizeBytes, long sizeBeforeBytes)204     protected ArtdDexoptResult createArtdDexoptResult(boolean cancelled, long wallTimeMs,
205             long cpuTimeMs, long sizeBytes, long sizeBeforeBytes) {
206         var result = new ArtdDexoptResult();
207         result.cancelled = cancelled;
208         result.wallTimeMs = wallTimeMs;
209         result.cpuTimeMs = cpuTimeMs;
210         result.sizeBytes = sizeBytes;
211         result.sizeBeforeBytes = sizeBeforeBytes;
212         return result;
213     }
214 
createArtdDexoptResult(boolean cancelled)215     protected ArtdDexoptResult createArtdDexoptResult(boolean cancelled) {
216         return createArtdDexoptResult(cancelled, 0 /* wallTimeMs */, 0 /* cpuTimeMs */,
217                 0 /* sizeBytes */, 0 /* sizeBeforeBytes */);
218     }
219 }
220