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.pm;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyInt;
23 import static org.mockito.ArgumentMatchers.anyString;
24 import static org.mockito.Mockito.doAnswer;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.spy;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 import static org.testng.Assert.assertThrows;
33 
34 import android.annotation.NonNull;
35 import android.annotation.Nullable;
36 import android.apex.ApexInfo;
37 import android.apex.ApexSessionInfo;
38 import android.apex.ApexSessionParams;
39 import android.apex.IApexService;
40 import android.content.pm.ApplicationInfo;
41 import android.content.pm.PackageManager;
42 import android.os.Build;
43 import android.os.Environment;
44 import android.os.RemoteException;
45 import android.os.ServiceSpecificException;
46 import android.platform.test.annotations.Presubmit;
47 
48 import androidx.test.filters.SmallTest;
49 import androidx.test.runner.AndroidJUnit4;
50 
51 import com.android.server.pm.parsing.PackageParser2;
52 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
53 import com.android.server.pm.pkg.AndroidPackage;
54 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
55 
56 import org.junit.Before;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 
61 import java.io.BufferedOutputStream;
62 import java.io.File;
63 import java.io.FileOutputStream;
64 import java.io.IOException;
65 import java.io.InputStream;
66 import java.io.OutputStream;
67 import java.util.List;
68 import java.util.Objects;
69 
70 @SmallTest
71 @Presubmit
72 @RunWith(AndroidJUnit4.class)
73 
74 public class ApexManagerTest {
75 
76     @Rule
77     public final MockSystemRule mMockSystem = new MockSystemRule();
78 
79     private static final String TEST_APEX_PKG = "com.android.apex.test";
80     private static final String TEST_APEX_FILE_NAME = "apex.test.apex";
81     private static final int TEST_SESSION_ID = 99999999;
82     private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
83     private ApexManager mApexManager;
84     private PackageParser2 mPackageParser2;
85 
86     private IApexService mApexService = mock(IApexService.class);
87 
88     private PackageManagerService mPmService;
89 
90     private InstallPackageHelper mInstallPackageHelper;
91 
92     @Before
setUp()93     public void setUp() throws Exception {
94         ApexManager.ApexManagerImpl managerImpl = spy(new ApexManager.ApexManagerImpl());
95         doReturn(mApexService).when(managerImpl).waitForApexService();
96         when(mApexService.getActivePackages()).thenReturn(new ApexInfo[0]);
97         mApexManager = managerImpl;
98         mPackageParser2 = new PackageParser2(null, null, null, new PackageParser2.Callback() {
99             @Override
100             public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
101                 return true;
102             }
103 
104             @Override
105             public boolean hasFeature(String feature) {
106                 return true;
107             }
108         });
109 
110         mMockSystem.system().stageNominalSystemState();
111         mPmService = new PackageManagerService(mMockSystem.mocks().getInjector(),
112                 false /*factoryTest*/,
113                 MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint,
114                 false /*isEngBuild*/,
115                 false /*isUserDebugBuild*/,
116                 Build.VERSION_CODES.CUR_DEVELOPMENT,
117                 Build.VERSION.INCREMENTAL);
118         mMockSystem.system().validateFinalState();
119         mInstallPackageHelper = new InstallPackageHelper(mPmService, mock(AppDataHelper.class));
120     }
121 
122     @NonNull
scanApexInfos(ApexInfo[] apexInfos)123     private List<ApexManager.ScanResult> scanApexInfos(ApexInfo[] apexInfos) {
124         return mInstallPackageHelper.scanApexPackages(apexInfos,
125                 ParsingPackageUtils.PARSE_IS_SYSTEM_DIR,
126                 PackageManagerService.SCAN_AS_SYSTEM, mPackageParser2,
127                 ParallelPackageParser.makeExecutorService());
128     }
129 
130     @Nullable
findActive(@onNull List<ApexManager.ScanResult> results)131     private ApexManager.ScanResult findActive(@NonNull List<ApexManager.ScanResult> results) {
132         return results.stream()
133                 .filter(it -> it.apexInfo.isActive)
134                 .filter(it -> Objects.equals(it.packageName, TEST_APEX_PKG))
135                 .findFirst()
136                 .orElse(null);
137     }
138 
139     @Nullable
findFactory(@onNull List<ApexManager.ScanResult> results, @NonNull String packageName)140     private ApexManager.ScanResult findFactory(@NonNull List<ApexManager.ScanResult> results,
141             @NonNull String packageName) {
142         return results.stream()
143                 .filter(it -> it.apexInfo.isFactory)
144                 .filter(it -> Objects.equals(it.packageName, packageName))
145                 .findFirst()
146                 .orElse(null);
147     }
148 
149     @NonNull
mockParsePackage(@onNull PackageParser2 parser, @NonNull ApexInfo apexInfo)150     private AndroidPackage mockParsePackage(@NonNull PackageParser2 parser,
151             @NonNull ApexInfo apexInfo) {
152         var flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
153         try {
154             var parsedPackage = parser.parsePackage(new File(apexInfo.modulePath), flags,
155                     /* useCaches= */ false);
156             ScanPackageUtils.applyPolicy(parsedPackage,
157                     PackageManagerService.SCAN_AS_APEX | PackageManagerService.SCAN_AS_SYSTEM,
158                     mPmService.getPlatformPackage(), /* isUpdatedSystemApp */ false);
159             // isUpdatedSystemApp is ignoreable above, only used for shared library adjustment
160             return parsedPackage.hideAsFinal();
161         } catch (PackageManagerException e) {
162             throw new RuntimeException(e);
163         }
164     }
165 
166     @Test
testScanActivePackage()167     public void testScanActivePackage() {
168         var apexInfos = createApexInfoForTestPkg(true, false);
169         var results = scanApexInfos(apexInfos);
170         var active = findActive(results);
171         var factory = findFactory(results, TEST_APEX_PKG);
172 
173         assertThat(active).isNotNull();
174         assertThat(active.packageName).isEqualTo(TEST_APEX_PKG);
175 
176         assertThat(factory).isNull();
177     }
178 
179     @Test
testScanFactoryPackage()180     public void testScanFactoryPackage() {
181         var apexInfos = createApexInfoForTestPkg(false, true);
182         var results = scanApexInfos(apexInfos);
183         var active = findActive(results);
184         var factory = findFactory(results, TEST_APEX_PKG);
185 
186         assertThat(factory).isNotNull();
187         assertThat(factory.packageName).contains(TEST_APEX_PKG);
188 
189         assertThat(active).isNull();
190     }
191 
192     @Test
testGetApexSystemServices()193     public void testGetApexSystemServices() {
194         ApexInfo[] apexInfo = new ApexInfo[]{
195                 createApexInfoForTestPkg(false, true, 1),
196                 // only active apex reports apex-system-service
197                 createApexInfoForTestPkg(true, false, 2),
198         };
199 
200         List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
201         mApexManager.notifyScanResult(scanResults);
202 
203         List<ApexSystemServiceInfo> services = mApexManager.getApexSystemServices();
204         assertThat(services).hasSize(1);
205         assertThat(services.stream().map(ApexSystemServiceInfo::getName).findFirst().orElse(null))
206                 .matches("com.android.apex.test.ApexSystemService");
207     }
208 
209     @Test
testIsApexPackage()210     public void testIsApexPackage() {
211         var apexInfos = createApexInfoForTestPkg(false, true);
212         var results = scanApexInfos(apexInfos);
213         var factory = findFactory(results, TEST_APEX_PKG);
214         assertThat(factory.pkg.isApex()).isTrue();
215     }
216 
217     @Test
testIsApexSupported()218     public void testIsApexSupported() {
219         assertThat(mApexManager.isApexSupported()).isTrue();
220     }
221 
222     @Test
testGetStagedSessionInfo()223     public void testGetStagedSessionInfo() throws RemoteException {
224         when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
225                 getFakeStagedSessionInfo());
226 
227         mApexManager.getStagedSessionInfo(TEST_SESSION_ID);
228         verify(mApexService, times(1)).getStagedSessionInfo(TEST_SESSION_ID);
229     }
230 
231     @Test
testGetStagedSessionInfo_unKnownStagedSessionId()232     public void testGetStagedSessionInfo_unKnownStagedSessionId() throws RemoteException {
233         when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
234                 getFakeUnknownSessionInfo());
235 
236         assertThat(mApexManager.getStagedSessionInfo(TEST_SESSION_ID)).isNull();
237     }
238 
239     @Test
testSubmitStagedSession_throwPackageManagerException()240     public void testSubmitStagedSession_throwPackageManagerException() throws RemoteException {
241         doAnswer(invocation -> {
242             throw new Exception();
243         }).when(mApexService).submitStagedSession(any(), any());
244 
245         assertThrows(PackageManagerException.class,
246                 () -> mApexManager.submitStagedSession(testParamsWithChildren()));
247     }
248 
249     @Test
testSubmitStagedSession_throwRunTimeException()250     public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
251         doThrow(RemoteException.class).when(mApexService).submitStagedSession(any(), any());
252 
253         assertThrows(RuntimeException.class,
254                 () -> mApexManager.submitStagedSession(testParamsWithChildren()));
255     }
256 
257     @Test
testGetStagedApexInfos_throwRunTimeException()258     public void testGetStagedApexInfos_throwRunTimeException() throws RemoteException {
259         doThrow(RemoteException.class).when(mApexService).getStagedApexInfos(any());
260 
261         assertThrows(RuntimeException.class,
262                 () -> mApexManager.getStagedApexInfos(testParamsWithChildren()));
263     }
264 
265     @Test
testGetStagedApexInfos_returnsEmptyArrayOnError()266     public void testGetStagedApexInfos_returnsEmptyArrayOnError() throws RemoteException {
267         doThrow(ServiceSpecificException.class).when(mApexService).getStagedApexInfos(any());
268 
269         assertThat(mApexManager.getStagedApexInfos(testParamsWithChildren())).hasLength(0);
270     }
271 
272     @Test
testMarkStagedSessionReady_throwPackageManagerException()273     public void testMarkStagedSessionReady_throwPackageManagerException() throws RemoteException {
274         doAnswer(invocation -> {
275             throw new Exception();
276         }).when(mApexService).markStagedSessionReady(anyInt());
277 
278         assertThrows(PackageManagerException.class,
279                 () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
280     }
281 
282     @Test
testMarkStagedSessionReady_throwRunTimeException()283     public void testMarkStagedSessionReady_throwRunTimeException() throws RemoteException {
284         doThrow(RemoteException.class).when(mApexService).markStagedSessionReady(anyInt());
285 
286         assertThrows(RuntimeException.class,
287                 () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
288     }
289 
290     @Test
testRevertActiveSessions_remoteException()291     public void testRevertActiveSessions_remoteException() throws RemoteException {
292         doThrow(RemoteException.class).when(mApexService).revertActiveSessions();
293 
294         try {
295             assertThat(mApexManager.revertActiveSessions()).isFalse();
296         } catch (Exception e) {
297             throw new AssertionError("ApexManager should not raise Exception");
298         }
299     }
300 
301     @Test
testMarkStagedSessionSuccessful_throwRemoteException()302     public void testMarkStagedSessionSuccessful_throwRemoteException() throws RemoteException {
303         doThrow(RemoteException.class).when(mApexService).markStagedSessionSuccessful(anyInt());
304 
305         assertThrows(RuntimeException.class,
306                 () -> mApexManager.markStagedSessionSuccessful(TEST_SESSION_ID));
307     }
308 
309     @Test
testUninstallApex_throwException_returnFalse()310     public void testUninstallApex_throwException_returnFalse() throws RemoteException {
311         doAnswer(invocation -> {
312             throw new Exception();
313         }).when(mApexService).unstagePackages(any());
314 
315         assertThat(mApexManager.uninstallApex(TEST_APEX_PKG)).isFalse();
316     }
317 
318     @Test
testReportErrorWithApkInApex()319     public void testReportErrorWithApkInApex() throws RemoteException {
320         when(mApexService.getActivePackages()).thenReturn(createApexInfoForTestPkg(true, true));
321         final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0);
322         assertThat(activeApex.apexModuleName).isEqualTo(TEST_APEX_PKG);
323 
324         ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
325         List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
326         mApexManager.notifyScanResult(scanResults);
327 
328         assertThat(mApexManager.getApkInApexInstallError(activeApex.apexModuleName)).isNull();
329         mApexManager.reportErrorWithApkInApex(activeApex.apexDirectory.getAbsolutePath(),
330                 "Some random error");
331         assertThat(mApexManager.getApkInApexInstallError(activeApex.apexModuleName))
332                 .isEqualTo("Some random error");
333     }
334 
335     /**
336      * registerApkInApex method checks if the prefix of base apk path contains the apex package
337      * name. When an apex package name is a prefix of another apex package name, e.g,
338      * com.android.media and com.android.mediaprovider, then we need to ensure apk inside apex
339      * mediaprovider does not get registered under apex media.
340      */
341     @Test
testRegisterApkInApexDoesNotRegisterSimilarPrefix()342     public void testRegisterApkInApexDoesNotRegisterSimilarPrefix() throws RemoteException {
343         when(mApexService.getActivePackages()).thenReturn(createApexInfoForTestPkg(true, true));
344         final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0);
345         assertThat(activeApex.apexModuleName).isEqualTo(TEST_APEX_PKG);
346 
347         AndroidPackage fakeApkInApex = mock(AndroidPackage.class);
348         when(fakeApkInApex.getBaseApkPath()).thenReturn("/apex/" + TEST_APEX_PKG + "randomSuffix");
349         when(fakeApkInApex.getPackageName()).thenReturn("randomPackageName");
350 
351         ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
352         List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
353         mApexManager.notifyScanResult(scanResults);
354 
355         assertThat(mApexManager.getApksInApex(activeApex.apexModuleName)).isEmpty();
356         mApexManager.registerApkInApex(fakeApkInApex);
357         assertThat(mApexManager.getApksInApex(activeApex.apexModuleName)).isEmpty();
358     }
359 
360     @Test
testInstallPackage_activeOnSystem()361     public void testInstallPackage_activeOnSystem() throws Exception {
362         ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
363                 /* isFactory= */ true, extractResource("test.apex_rebootless_v1",
364                         "test.rebootless_apex_v1.apex"));
365         ApexInfo[] apexInfo = new ApexInfo[]{activeApexInfo};
366         var results = scanApexInfos(apexInfo);
367 
368         File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
369         ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
370                 /* isFactory= */ false, finalApex);
371         when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo);
372 
373         File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
374         newApexInfo = mApexManager.installPackage(installedApex);
375 
376         var newPkg = mockParsePackage(mPackageParser2, newApexInfo);
377         assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
378         assertThat(newPkg.getLongVersionCode()).isEqualTo(2);
379 
380         var factoryPkg = mockParsePackage(mPackageParser2,
381                 findFactory(results, "test.apex.rebootless").apexInfo);
382         assertThat(factoryPkg.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath);
383         assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
384         assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
385     }
386 
387     @Test
testInstallPackage_activeOnData()388     public void testInstallPackage_activeOnData() throws Exception {
389         ApexInfo factoryApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ false,
390                 /* isFactory= */ true, extractResource("test.apex_rebootless_v1",
391                         "test.rebootless_apex_v1.apex"));
392         ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
393                 /* isFactory= */ false, extractResource("test.apex.rebootless@1",
394                         "test.rebootless_apex_v1.apex"));
395         ApexInfo[] apexInfo = new ApexInfo[]{factoryApexInfo, activeApexInfo};
396         var results = scanApexInfos(apexInfo);
397 
398         File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
399         ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
400                 /* isFactory= */ false, finalApex);
401         when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo);
402 
403         File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
404         newApexInfo = mApexManager.installPackage(installedApex);
405 
406         var newPkg = mockParsePackage(mPackageParser2, newApexInfo);
407         assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
408         assertThat(newPkg.getLongVersionCode()).isEqualTo(2);
409 
410         var factoryPkg = mockParsePackage(mPackageParser2,
411                 findFactory(results, "test.apex.rebootless").apexInfo);
412         assertThat(factoryPkg.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath);
413         assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
414         assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
415     }
416 
417     @Test
testInstallPackageBinderCallFails()418     public void testInstallPackageBinderCallFails() throws Exception {
419         when(mApexService.installAndActivatePackage(anyString())).thenThrow(
420                 new RuntimeException("install failed :("));
421 
422         File installedApex = extractResource("test.apex_rebootless_v1",
423                 "test.rebootless_apex_v1.apex");
424         assertThrows(PackageManagerException.class,
425                 () -> mApexManager.installPackage(installedApex));
426     }
427 
428     @Test
testGetActivePackageNameForApexModuleName()429     public void testGetActivePackageNameForApexModuleName() {
430         final String moduleName = "com.android.module_name";
431 
432         ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
433         apexInfo[0].moduleName = moduleName;
434         List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
435         mApexManager.notifyScanResult(scanResults);
436 
437         assertThat(mApexManager.getActivePackageNameForApexModuleName(moduleName))
438                 .isEqualTo(TEST_APEX_PKG);
439     }
440 
441     @Test
testGetBackingApexFiles()442     public void testGetBackingApexFiles() throws Exception {
443         final ApexInfo apex = createApexInfoForTestPkg(true, true, 37);
444         when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex});
445 
446         final File backingApexFile = mApexManager.getBackingApexFile(
447                 new File(mMockSystem.system().getApexDirectory(),
448                         TEST_APEX_PKG + "/apk/App/App.apk"));
449         assertThat(backingApexFile.getAbsolutePath()).isEqualTo(apex.modulePath);
450     }
451 
452     @Test
testGetBackingApexFile_fileNotOnApexMountPoint_returnsNull()453     public void testGetBackingApexFile_fileNotOnApexMountPoint_returnsNull() {
454         File result = mApexManager.getBackingApexFile(
455                 new File("/data/local/tmp/whatever/does-not-matter"));
456         assertThat(result).isNull();
457     }
458 
459     @Test
testGetBackingApexFiles_unknownApex_returnsNull()460     public void testGetBackingApexFiles_unknownApex_returnsNull() throws Exception {
461         final ApexInfo apex = createApexInfoForTestPkg(true, true, 37);
462         when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex});
463 
464         final File backingApexFile = mApexManager.getBackingApexFile(
465                 new File(mMockSystem.system().getApexDirectory(), "com.wrong.apex/apk/App"));
466         assertThat(backingApexFile).isNull();
467     }
468 
469     @Test
testGetBackingApexFiles_topLevelApexDir_returnsNull()470     public void testGetBackingApexFiles_topLevelApexDir_returnsNull() {
471         assertThat(mApexManager.getBackingApexFile(Environment.getApexDirectory())).isNull();
472         assertThat(mApexManager.getBackingApexFile(new File("/apex/"))).isNull();
473         assertThat(mApexManager.getBackingApexFile(new File("/apex//"))).isNull();
474     }
475 
476     @Test
testGetBackingApexFiles_flattenedApex()477     public void testGetBackingApexFiles_flattenedApex() {
478         ApexManager flattenedApexManager = new ApexManager.ApexManagerFlattenedApex();
479         final File backingApexFile = flattenedApexManager.getBackingApexFile(
480                 new File(mMockSystem.system().getApexDirectory(),
481                         "com.android.apex.cts.shim/app/CtsShim/CtsShim.apk"));
482         assertThat(backingApexFile).isNull();
483     }
484 
485     @Test
testActiveApexChanged()486     public void testActiveApexChanged() throws RemoteException {
487         ApexInfo apex1 = createApexInfo(
488                 "com.apex1", 37, true, true, new File("/data/apex/active/com.apex@37.apex"));
489         apex1.activeApexChanged = true;
490         apex1.preinstalledModulePath = apex1.modulePath;
491         when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex1});
492         final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0);
493         assertThat(activeApex.apexModuleName).isEqualTo("com.apex1");
494         assertThat(activeApex.activeApexChanged).isTrue();
495     }
496 
createApexInfoForTestPkg(boolean isActive, boolean isFactory, int version)497     private ApexInfo createApexInfoForTestPkg(boolean isActive, boolean isFactory, int version) {
498         File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME);
499         ApexInfo apexInfo = new ApexInfo();
500         apexInfo.isActive = isActive;
501         apexInfo.isFactory = isFactory;
502         apexInfo.moduleName = TEST_APEX_PKG;
503         apexInfo.modulePath = apexFile.getPath();
504         apexInfo.versionCode = version;
505         apexInfo.preinstalledModulePath = apexFile.getPath();
506         return apexInfo;
507     }
508 
createApexInfoForTestPkg(boolean isActive, boolean isFactory)509     private ApexInfo[] createApexInfoForTestPkg(boolean isActive, boolean isFactory) {
510         return new ApexInfo[]{createApexInfoForTestPkg(isActive, isFactory, 191000070)};
511     }
512 
createApexInfo(String moduleName, int versionCode, boolean isActive, boolean isFactory, File apexFile)513     private ApexInfo createApexInfo(String moduleName, int versionCode, boolean isActive,
514             boolean isFactory, File apexFile) {
515         ApexInfo apexInfo = new ApexInfo();
516         apexInfo.moduleName = moduleName;
517         apexInfo.versionCode = versionCode;
518         apexInfo.isActive = isActive;
519         apexInfo.isFactory = isFactory;
520         apexInfo.modulePath = apexFile.getPath();
521         apexInfo.preinstalledModulePath = apexFile.getPath();
522         return apexInfo;
523     }
524 
getFakeStagedSessionInfo()525     private ApexSessionInfo getFakeStagedSessionInfo() {
526         ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
527         stagedSessionInfo.sessionId = TEST_SESSION_ID;
528         stagedSessionInfo.isStaged = true;
529 
530         return stagedSessionInfo;
531     }
532 
getFakeUnknownSessionInfo()533     private ApexSessionInfo getFakeUnknownSessionInfo() {
534         ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
535         stagedSessionInfo.sessionId = TEST_SESSION_ID;
536         stagedSessionInfo.isUnknown = true;
537 
538         return stagedSessionInfo;
539     }
540 
testParamsWithChildren()541     private static ApexSessionParams testParamsWithChildren() {
542         ApexSessionParams params = new ApexSessionParams();
543         params.sessionId = TEST_SESSION_ID;
544         params.childSessionIds = TEST_CHILD_SESSION_ID;
545         return params;
546     }
547 
548     // Extracts the binary data from a resource and writes it to a temp file
extractResource(String baseName, String fullResourceName)549     private static File extractResource(String baseName, String fullResourceName) {
550         File file;
551         try {
552             file = File.createTempFile(baseName, ".apex");
553         } catch (IOException e) {
554             throw new AssertionError("CreateTempFile IOException" + e);
555         }
556 
557         try (
558                 InputStream in = ApexManager.class.getClassLoader()
559                         .getResourceAsStream(fullResourceName);
560                 OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
561             if (in == null) {
562                 throw new IllegalArgumentException("Resource not found: " + fullResourceName);
563             }
564             byte[] buf = new byte[65536];
565             int chunkSize;
566             while ((chunkSize = in.read(buf)) != -1) {
567                 out.write(buf, 0, chunkSize);
568             }
569             return file;
570         } catch (IOException e) {
571             throw new AssertionError("Exception while converting stream to file" + e);
572         }
573     }
574 }
575