PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/android/com/facebook/buck/android/support/exopackage/ExopackageSoLoader.java

https://gitlab.com/smartether/buck
Java | 203 lines | 154 code | 29 blank | 20 comment | 28 complexity | 81669c265c84baaba0c7102165d5a5fd MD5 | raw file
  1. /*
  2. * Copyright 2014-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. * not use this file except in compliance with the License. You may obtain
  6. * 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, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations
  14. * under the License.
  15. */
  16. package com.facebook.buck.android.support.exopackage;
  17. import java.io.BufferedInputStream;
  18. import java.io.BufferedOutputStream;
  19. import java.io.BufferedReader;
  20. import java.io.File;
  21. import java.io.FileInputStream;
  22. import java.io.FileOutputStream;
  23. import java.io.FileReader;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27. import java.util.HashMap;
  28. import java.util.Map;
  29. import android.content.Context;
  30. import android.os.Build;
  31. import android.util.Log;
  32. /**
  33. * Loads native library files installed by the exopackage installer. This class requires
  34. * initialization before use; {@link ExopackageApplication#attachBaseContext} is responsible
  35. * for calling {@link #init} so that application-specific code doesn't need to.
  36. */
  37. public class ExopackageSoLoader {
  38. private static final String TAG = "ExopackageSoLoader";
  39. private static boolean initialized = false;
  40. private static String nativeLibsDir = null;
  41. private static File privateNativeLibsDir = null;
  42. private static Map<String, String> abi1Libraries = new HashMap<String, String>();
  43. private static Map<String, String> abi2Libraries = new HashMap<String, String>();
  44. private ExopackageSoLoader() {}
  45. public static void init(Context context) {
  46. if (initialized) {
  47. Log.d(TAG, "init() already called, so nothing to do.");
  48. return;
  49. }
  50. nativeLibsDir = "/data/local/tmp/exopackage/" + context.getPackageName() + "/native-libs/";
  51. verifyMetadataFile();
  52. preparePrivateDirectory(context);
  53. parseMetadata();
  54. initialized = true;
  55. }
  56. private static void verifyMetadataFile() {
  57. File abiMetadata = getAbi1Metadata();
  58. if (abiMetadata.exists()) {
  59. return;
  60. }
  61. abiMetadata = getAbi2Metadata();
  62. if (abiMetadata == null || abiMetadata.exists()) {
  63. return;
  64. }
  65. throw new RuntimeException("Either 'native' exopackage is not turned on for this build, " +
  66. "or the installation did not complete successfully.");
  67. }
  68. private static void preparePrivateDirectory(Context context) {
  69. privateNativeLibsDir = context.getDir("exo-libs", Context.MODE_PRIVATE);
  70. for (File file : privateNativeLibsDir.listFiles()) {
  71. file.delete();
  72. }
  73. }
  74. private static void parseMetadata() {
  75. doParseMetadata(getAbi1Metadata(), abi1Libraries);
  76. doParseMetadata(getAbi2Metadata(), abi2Libraries);
  77. }
  78. private static void doParseMetadata(File metadata, Map<String, String> libraries) {
  79. if (metadata == null || !metadata.exists()) {
  80. return;
  81. }
  82. BufferedReader br = null;
  83. try {
  84. br = new BufferedReader(new FileReader(metadata));
  85. String line;
  86. try {
  87. while ((line = br.readLine()) != null) {
  88. line = line.trim();
  89. if (line.isEmpty()) {
  90. continue;
  91. }
  92. int spaceIndex = line.indexOf(' ');
  93. if (spaceIndex == -1) {
  94. throw new RuntimeException("Error parsing metadata.txt; invalid line: " + line);
  95. }
  96. String libname = line.substring(0, spaceIndex);
  97. String filename = line.substring(spaceIndex + 1);
  98. libraries.put(libname, filename);
  99. }
  100. } finally {
  101. br.close();
  102. }
  103. } catch (IOException e) {
  104. throw new RuntimeException(e);
  105. }
  106. }
  107. public static void loadLibrary(String shortName) throws UnsatisfiedLinkError {
  108. if (!initialized) {
  109. Log.d(TAG, "ExopackageSoLoader not initialized, falling back to System.loadLibrary()");
  110. System.loadLibrary(shortName);
  111. return;
  112. }
  113. String libname = shortName.startsWith("lib") ? shortName : "lib" + shortName;
  114. File libraryFile = copySoFileIfRequired(libname);
  115. if (libraryFile == null) {
  116. throw new UnsatisfiedLinkError("Could not find library file for either ABIs.");
  117. }
  118. String path = libraryFile.getAbsolutePath();
  119. Log.d(TAG, "Attempting to load library: " + path);
  120. System.load(path);
  121. Log.d(TAG, "Successfully loaded library: " + path);
  122. }
  123. private static File copySoFileIfRequired(String libname) {
  124. File libraryFile = new File(privateNativeLibsDir, libname + ".so");
  125. if (libraryFile.exists()) {
  126. return libraryFile;
  127. }
  128. if (!abi1Libraries.containsKey(libname) && !abi2Libraries.containsKey(libname)) {
  129. return null;
  130. }
  131. String abiDir;
  132. String sourceFilename;
  133. if (abi1Libraries.containsKey(libname)) {
  134. sourceFilename = abi1Libraries.get(libname);
  135. abiDir = Build.CPU_ABI;
  136. } else {
  137. sourceFilename = abi2Libraries.get(libname);
  138. abiDir = Build.CPU_ABI2;
  139. }
  140. String sourcePath = nativeLibsDir + abiDir + "/" + sourceFilename;
  141. try {
  142. InputStream in = null;
  143. OutputStream out = null;
  144. try {
  145. in = new BufferedInputStream(new FileInputStream(sourcePath));
  146. out = new BufferedOutputStream(new FileOutputStream(libraryFile));
  147. byte[] buffer = new byte[4 * 1024];
  148. int len;
  149. while ((len = in.read(buffer)) > 0) {
  150. out.write(buffer, 0, len);
  151. }
  152. } finally {
  153. if (in != null) {
  154. in.close();
  155. }
  156. if (out != null) {
  157. out.close();
  158. }
  159. }
  160. } catch (IOException e) {
  161. throw new RuntimeException(e);
  162. }
  163. return libraryFile;
  164. }
  165. private static File getAbi1Metadata() {
  166. return new File(nativeLibsDir + Build.CPU_ABI + "/metadata.txt");
  167. }
  168. private static File getAbi2Metadata() {
  169. if (Build.CPU_ABI2.equals("unknown")) {
  170. return null;
  171. }
  172. return new File(nativeLibsDir + Build.CPU_ABI2 + "/metadata.txt");
  173. }
  174. }