1 /*
2  * Copyright (C) 2021 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 android.compat.testing.app;
18 
19 import static org.junit.Assume.assumeTrue;
20 
21 import android.app.Instrumentation;
22 import android.content.Context;
23 import android.content.pm.SharedLibraryInfo;
24 import android.util.Log;
25 
26 import androidx.test.platform.app.InstrumentationRegistry;
27 import androidx.test.runner.AndroidJUnit4;
28 
29 import com.android.modules.utils.build.SdkLevel;
30 
31 import com.google.common.collect.ImmutableList;
32 import com.google.common.collect.ImmutableSet;
33 
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 
39 import java.io.File;
40 import java.nio.file.Files;
41 import java.nio.file.Path;
42 import java.util.List;
43 import java.util.Locale;
44 import java.util.Set;
45 
46 /**
47  * Device-side helper app for obtaining shared libraries.
48  *
49  * <p>It is not technically a test as it simply collects information, but it simplifies the usage
50  * and communication with host-side tests.
51  */
52 @RunWith(AndroidJUnit4.class)
53 public class SharedLibraryInfoDeviceTest {
54 
55     private static final String TAG = "SharedLibraryInfoDeviceTest";
56     private static final Set<String> T_PLUS_EXCLUDES = ImmutableSet.of(
57             // This shared library's code is added to the bootclasspath in T+ by the
58             // AdServices mainline module.
59             "android.ext.adservices"
60         );
61 
62     private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
63     private final Context context = instrumentation.getTargetContext();
64 
65     @Before
before()66     public void before() {
67         assumeTrue(SdkLevel.isAtLeastS());
68         instrumentation.getUiAutomation().adoptShellPermissionIdentity();
69     }
70 
71     @After
after()72     public void after() {
73         instrumentation.getUiAutomation().dropShellPermissionIdentity();
74     }
75 
76     /**
77      * Collects details about all shared libraries on the device and writes them to disk.
78      */
79     @Test
collectSharedLibraryPaths()80     public void collectSharedLibraryPaths() throws Exception {
81         List<SharedLibraryInfo> sharedLibraries =
82                 context.getPackageManager().getSharedLibraries(0);
83 
84         ImmutableList.Builder<String> content = ImmutableList.builder();
85         for (SharedLibraryInfo sharedLibrary : sharedLibraries) {
86             if (!canSafelyIgnoreSharedLibrary(sharedLibrary)) {
87                 content.add(String.format(Locale.US, "%s %d %d %s",
88                         sharedLibrary.getName(),
89                         sharedLibrary.getType(),
90                         sharedLibrary.getLongVersion(),
91                         String.join(" ", sharedLibrary.getAllCodePaths())));
92             }
93         }
94 
95         Path detailsFilepath = new File("/sdcard/shared-libs.txt").toPath();
96         ImmutableList<String> lines = content.build();
97         Log.i(TAG, String.format("Writing details about %d shared libraries to %s",
98                 lines.size(), detailsFilepath));
99         Files.write(detailsFilepath, lines);
100     }
101 
canSafelyIgnoreSharedLibrary(SharedLibraryInfo sharedLibrary)102     private boolean canSafelyIgnoreSharedLibrary(SharedLibraryInfo sharedLibrary) {
103         if (sharedLibrary.isNative()) {
104             return true;
105         }
106         if (SdkLevel.isAtLeastT()) {
107             return T_PLUS_EXCLUDES.contains(sharedLibrary.getName());
108         }
109         return false;
110     }
111 
112 }
113