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