/android/com/facebook/buck/android/support/exopackage/ExopackageSoLoader.java
Java | 203 lines | 154 code | 29 blank | 20 comment | 28 complexity | 81669c265c84baaba0c7102165d5a5fd MD5 | raw file
- /*
- * Copyright 2014-present Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
- package com.facebook.buck.android.support.exopackage;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.FileReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.util.HashMap;
- import java.util.Map;
- import android.content.Context;
- import android.os.Build;
- import android.util.Log;
- /**
- * Loads native library files installed by the exopackage installer. This class requires
- * initialization before use; {@link ExopackageApplication#attachBaseContext} is responsible
- * for calling {@link #init} so that application-specific code doesn't need to.
- */
- public class ExopackageSoLoader {
- private static final String TAG = "ExopackageSoLoader";
- private static boolean initialized = false;
- private static String nativeLibsDir = null;
- private static File privateNativeLibsDir = null;
- private static Map<String, String> abi1Libraries = new HashMap<String, String>();
- private static Map<String, String> abi2Libraries = new HashMap<String, String>();
- private ExopackageSoLoader() {}
- public static void init(Context context) {
- if (initialized) {
- Log.d(TAG, "init() already called, so nothing to do.");
- return;
- }
- nativeLibsDir = "/data/local/tmp/exopackage/" + context.getPackageName() + "/native-libs/";
- verifyMetadataFile();
- preparePrivateDirectory(context);
- parseMetadata();
- initialized = true;
- }
- private static void verifyMetadataFile() {
- File abiMetadata = getAbi1Metadata();
- if (abiMetadata.exists()) {
- return;
- }
- abiMetadata = getAbi2Metadata();
- if (abiMetadata == null || abiMetadata.exists()) {
- return;
- }
- throw new RuntimeException("Either 'native' exopackage is not turned on for this build, " +
- "or the installation did not complete successfully.");
- }
- private static void preparePrivateDirectory(Context context) {
- privateNativeLibsDir = context.getDir("exo-libs", Context.MODE_PRIVATE);
- for (File file : privateNativeLibsDir.listFiles()) {
- file.delete();
- }
- }
- private static void parseMetadata() {
- doParseMetadata(getAbi1Metadata(), abi1Libraries);
- doParseMetadata(getAbi2Metadata(), abi2Libraries);
- }
- private static void doParseMetadata(File metadata, Map<String, String> libraries) {
- if (metadata == null || !metadata.exists()) {
- return;
- }
- BufferedReader br = null;
- try {
- br = new BufferedReader(new FileReader(metadata));
- String line;
- try {
- while ((line = br.readLine()) != null) {
- line = line.trim();
- if (line.isEmpty()) {
- continue;
- }
- int spaceIndex = line.indexOf(' ');
- if (spaceIndex == -1) {
- throw new RuntimeException("Error parsing metadata.txt; invalid line: " + line);
- }
- String libname = line.substring(0, spaceIndex);
- String filename = line.substring(spaceIndex + 1);
- libraries.put(libname, filename);
- }
- } finally {
- br.close();
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- public static void loadLibrary(String shortName) throws UnsatisfiedLinkError {
- if (!initialized) {
- Log.d(TAG, "ExopackageSoLoader not initialized, falling back to System.loadLibrary()");
- System.loadLibrary(shortName);
- return;
- }
- String libname = shortName.startsWith("lib") ? shortName : "lib" + shortName;
- File libraryFile = copySoFileIfRequired(libname);
- if (libraryFile == null) {
- throw new UnsatisfiedLinkError("Could not find library file for either ABIs.");
- }
- String path = libraryFile.getAbsolutePath();
- Log.d(TAG, "Attempting to load library: " + path);
- System.load(path);
- Log.d(TAG, "Successfully loaded library: " + path);
- }
- private static File copySoFileIfRequired(String libname) {
- File libraryFile = new File(privateNativeLibsDir, libname + ".so");
- if (libraryFile.exists()) {
- return libraryFile;
- }
- if (!abi1Libraries.containsKey(libname) && !abi2Libraries.containsKey(libname)) {
- return null;
- }
- String abiDir;
- String sourceFilename;
- if (abi1Libraries.containsKey(libname)) {
- sourceFilename = abi1Libraries.get(libname);
- abiDir = Build.CPU_ABI;
- } else {
- sourceFilename = abi2Libraries.get(libname);
- abiDir = Build.CPU_ABI2;
- }
- String sourcePath = nativeLibsDir + abiDir + "/" + sourceFilename;
- try {
- InputStream in = null;
- OutputStream out = null;
- try {
- in = new BufferedInputStream(new FileInputStream(sourcePath));
- out = new BufferedOutputStream(new FileOutputStream(libraryFile));
- byte[] buffer = new byte[4 * 1024];
- int len;
- while ((len = in.read(buffer)) > 0) {
- out.write(buffer, 0, len);
- }
- } finally {
- if (in != null) {
- in.close();
- }
- if (out != null) {
- out.close();
- }
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return libraryFile;
- }
- private static File getAbi1Metadata() {
- return new File(nativeLibsDir + Build.CPU_ABI + "/metadata.txt");
- }
- private static File getAbi2Metadata() {
- if (Build.CPU_ABI2.equals("unknown")) {
- return null;
- }
- return new File(nativeLibsDir + Build.CPU_ABI2 + "/metadata.txt");
- }
- }