Release React Native for Android

This is an early release and there are several things that are known
not to work if you're porting your iOS app to Android.

See the Known Issues guide on the website.

We will work with the community to reach platform parity with iOS.
This commit is contained in:
Martin Konicek
2015-09-14 15:35:58 +01:00
parent c372dab213
commit 42eb5464fd
571 changed files with 44550 additions and 116 deletions
@@ -0,0 +1,237 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.soloader;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.HashSet;
import java.util.ArrayList;
import java.io.FileNotFoundException;
import java.util.Set;
import javax.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.os.StatFs;
import android.util.Log;
import android.content.pm.ApplicationInfo;
/**
* Note that {@link com.facebook.base.app.DelegatingApplication} will automatically register itself
* with SoLoader before running application-specific code; most applications do not need to call
* {@link #init} explicitly.
*/
@SuppressLint({
"BadMethodUse-android.util.Log.v",
"BadMethodUse-android.util.Log.d",
"BadMethodUse-android.util.Log.i",
"BadMethodUse-android.util.Log.w",
"BadMethodUse-android.util.Log.e",
})
public class SoLoader {
/* package */ static final String TAG = "SoLoader";
/* package */ static final boolean DEBUG = false;
/**
* Ordered list of sources to consult when trying to load a shared library or one of its
* dependencies. {@code null} indicates that SoLoader is uninitialized.
*/
@Nullable private static SoSource[] sSoSources = null;
/**
* Records the sonames (e.g., "libdistract.so") of shared libraries we've loaded.
*/
private static final Set<String> sLoadedLibraries = new HashSet<>();
/**
* Initializes native code loading for this app; this class's other static facilities cannot be
* used until this {@link #init} is called. This method is idempotent: calls after the first are
* ignored.
*
* @param context - application context.
* @param isNativeExopackageEnabled - whether native exopackage feature is enabled in the build.
*/
public static synchronized void init(@Nullable Context context, boolean isNativeExopackageEnabled) {
if (sSoSources == null) {
ArrayList<SoSource> soSources = new ArrayList<>();
//
// Add SoSource objects for each of the system library directories.
//
String LD_LIBRARY_PATH = System.getenv("LD_LIBRARY_PATH");
if (LD_LIBRARY_PATH == null) {
LD_LIBRARY_PATH = "/vendor/lib:/system/lib";
}
String[] systemLibraryDirectories = LD_LIBRARY_PATH.split(":");
for (int i = 0; i < systemLibraryDirectories.length; ++i) {
// Don't pass DirectorySoSource.RESOLVE_DEPENDENCIES for directories we find on
// LD_LIBRARY_PATH: Bionic's dynamic linker is capable of correctly resolving dependencies
// these libraries have on each other, so doing that ourselves would be a waste.
File systemSoDirectory = new File(systemLibraryDirectories[i]);
soSources.add(
new DirectorySoSource(
systemSoDirectory,
DirectorySoSource.ON_LD_LIBRARY_PATH));
}
//
// We can only proceed forward if we have a Context. The prominent case
// where we don't have a Context is barebones dalvikvm instantiations. In
// that case, the caller is responsible for providing a correct LD_LIBRARY_PATH.
//
if (context != null) {
//
// Prepend our own SoSource for our own DSOs.
//
ApplicationInfo applicationInfo = context.getApplicationInfo();
boolean isSystemApplication =
(applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 &&
(applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0;
try {
if (isNativeExopackageEnabled) {
soSources.add(0, new ExoSoSource(context));
} else if (isSystemApplication) {
soSources.add(0, new ApkSoSource(context));
} else {
// Delete the old libs directory if we don't need it.
SysUtil.dumbDeleteRecrusive(SysUtil.getLibsDirectory(context));
int ourSoSourceFlags = 0;
// On old versions of Android, Bionic doesn't add our library directory to its internal
// search path, and the system doesn't resolve dependencies between modules we ship. On
// these systems, we resolve dependencies ourselves. On other systems, Bionic's built-in
// resolver suffices.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
ourSoSourceFlags |= DirectorySoSource.RESOLVE_DEPENDENCIES;
}
SoSource ourSoSource = new DirectorySoSource(
new File(applicationInfo.nativeLibraryDir),
ourSoSourceFlags);
soSources.add(0, ourSoSource);
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
sSoSources = soSources.toArray(new SoSource[soSources.size()]);
}
}
/**
* Turn shared-library loading into a no-op. Useful in special circumstances.
*/
public static void setInTestMode() {
sSoSources = new SoSource[]{new NoopSoSource()};
}
/**
* Load a shared library, initializing any JNI binding it contains.
*
* @param shortName Name of library to find, without "lib" prefix or ".so" suffix
*/
public static synchronized void loadLibrary(String shortName)
throws UnsatisfiedLinkError
{
if (sSoSources == null) {
// This should never happen during normal operation,
// but if we're running in a non-Android environment,
// fall back to System.loadLibrary.
if ("http://www.android.com/".equals(System.getProperty("java.vendor.url"))) {
// This will throw.
assertInitialized();
} else {
// Not on an Android system. Ask the JVM to load for us.
System.loadLibrary(shortName);
return;
}
}
try {
loadLibraryBySoName(System.mapLibraryName(shortName), 0);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
/**
* Unpack library and its dependencies, returning the location of the unpacked library file. All
* non-system dependencies of the given library will either be on LD_LIBRARY_PATH or will be in
* the same directory as the returned File.
*
* @param shortName Name of library to find, without "lib" prefix or ".so" suffix
* @return Unpacked DSO location
*/
public static File unpackLibraryAndDependencies(String shortName)
throws UnsatisfiedLinkError
{
assertInitialized();
try {
return unpackLibraryBySoName(System.mapLibraryName(shortName));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
/* package */ static void loadLibraryBySoName(String soName, int loadFlags) throws IOException {
int result = sLoadedLibraries.contains(soName)
? SoSource.LOAD_RESULT_LOADED
: SoSource.LOAD_RESULT_NOT_FOUND;
for (int i = 0; result == SoSource.LOAD_RESULT_NOT_FOUND && i < sSoSources.length; ++i) {
result = sSoSources[i].loadLibrary(soName, loadFlags);
}
if (result == SoSource.LOAD_RESULT_NOT_FOUND) {
throw new UnsatisfiedLinkError("could find DSO to load: " + soName);
}
if (result == SoSource.LOAD_RESULT_LOADED) {
sLoadedLibraries.add(soName);
}
}
/* package */ static File unpackLibraryBySoName(String soName) throws IOException {
for (int i = 0; i < sSoSources.length; ++i) {
File unpacked = sSoSources[i].unpackLibrary(soName);
if (unpacked != null) {
return unpacked;
}
}
throw new FileNotFoundException(soName);
}
private static void assertInitialized() {
if (sSoSources == null) {
throw new RuntimeException("SoLoader.init() not yet called");
}
}
}