1 /* 2 * Copyright 2020 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.test.usesnativesharedlibrary; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertThat; 21 import static org.hamcrest.core.Is.is; 22 23 import android.os.Build; 24 import com.android.compatibility.common.util.CddTest; 25 import com.android.compatibility.common.util.PropertyUtil; 26 27 import androidx.test.core.app.ApplicationProvider; 28 import org.junit.Before; 29 import org.junit.Test; 30 import org.junit.runner.RunWith; 31 import org.junit.runners.JUnit4; 32 33 import java.io.BufferedReader; 34 import java.io.IOException; 35 import java.io.InputStreamReader; 36 import java.nio.file.Files; 37 import java.nio.file.Paths; 38 import java.util.ArrayList; 39 import java.util.Collections; 40 import java.util.List; 41 import java.util.Set; 42 import java.util.stream.Collectors; 43 import java.util.stream.Stream; 44 /** 45 * Tests if native shared libs are loadable or un-loadable as expected. The list of loadable libs is 46 * in the asset file <code>available.txt</code> and the list of un-loadable libs is in the asset 47 * file <code>unavailable.txt</code>. The files are dynamically created by the host-side test 48 * <code>UsesNativeLibraryTestCase</code>. 49 */ 50 @RunWith(JUnit4.class) 51 public class LoadTest { libNamesFromAssetFile(String filename)52 private List<String> libNamesFromAssetFile(String filename) { 53 List<String> result = new ArrayList<>(); 54 try (BufferedReader reader = new BufferedReader(new InputStreamReader( 55 ApplicationProvider.getApplicationContext().getAssets().open(filename)))) { 56 String line; 57 while ((line = reader.readLine()) != null) { 58 if (!line.isEmpty() && line.startsWith("lib") && line.endsWith(".so")) { 59 // libfoo.so -> foo because that's what System.loadLibrary accepts 60 result.add(line.substring(3, line.length()-3)); 61 } 62 } 63 } catch (Exception e) { 64 throw new RuntimeException(e); 65 } 66 return result; 67 } 68 vendorPublicLibraries()69 private Set<String> vendorPublicLibraries() { 70 try (Stream<String> lines = Files.lines(Paths.get("/vendor/etc/public.libraries.txt"))) { 71 return lines. 72 filter(line -> { 73 // filter-out empty lines or comment lines that start with # 74 String strip = line.trim(); 75 return !strip.isEmpty() && !strip.startsWith("#"); 76 }). 77 // line format is "name [bitness]". Extract the name part. 78 map(line -> line.trim().split("\\s+")[0]). 79 collect(Collectors.toSet()); 80 } catch (IOException e) { 81 return Collections.emptySet(); 82 } 83 } 84 85 /** 86 * Tests if libs listed in available.txt are all loadable 87 */ 88 @CddTest(requirement="3.6/C-1-1,C-1-2") 89 @Test testAvailableLibrariesAreLoaded()90 public void testAvailableLibrariesAreLoaded() { 91 List<String> unexpected = new ArrayList<>(); 92 for (String lib : libNamesFromAssetFile("available.txt")) { 93 try { 94 System.loadLibrary(lib); 95 } catch (Throwable t) { 96 if (!PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.R)) { 97 // Some old vendor.img might have stable entries in ./etc/public.libraries.txt 98 // Don't emit error in that case. 99 String libName = "lib" + lib + ".so"; 100 boolean notFound = t.getMessage().equals("dlopen failed: library \"" + libName 101 + "\" not found"); 102 boolean isVendorPublicLib = vendorPublicLibraries().contains(libName); 103 if (isVendorPublicLib && notFound) { 104 continue; 105 } 106 } 107 unexpected.add(t.getMessage()); 108 } 109 }; 110 assertThat("Some libraries failed to load. Libraries shown below are listed in " + 111 "/vendor/public.libraries.txt or /system/etc/public.libraries-COMPANYNAME.txt " + 112 "as public libraries, but they may not exist or inaccessible. " + 113 "You may fix this by unlisting them from the txt files" 114 , unexpected, is(Collections.emptyList())); 115 } 116 117 /** 118 * Tests if libs listed in unavailable.txt are all non-loadable 119 */ 120 @CddTest(requirement="3.6/C-1-1,C-1-2") 121 @Test testUnavailableLibrariesAreNotLoaded()122 public void testUnavailableLibrariesAreNotLoaded() { 123 List<String> loadedLibs = new ArrayList<>(); 124 List<String> unexpectedFailures = new ArrayList<>(); 125 for (String lib : libNamesFromAssetFile("unavailable.txt")) { 126 try { 127 System.loadLibrary(lib); 128 loadedLibs.add("lib" + lib + ".so"); 129 } catch (UnsatisfiedLinkError e) { 130 // This is expected 131 } catch (Throwable t) { 132 unexpectedFailures.add(t.getMessage()); 133 } 134 }; 135 assertThat("Some unavailable libraries were loaded", loadedLibs, is(Collections.emptyList())); 136 assertThat("Unexpected errors occurred", unexpectedFailures, is(Collections.emptyList())); 137 } 138 } 139