diff --git a/java/com/facebook/soloader/ExternalSoMapping.java b/java/com/facebook/soloader/ExternalSoMapping.java new file mode 100644 index 0000000..5b45904 --- /dev/null +++ b/java/com/facebook/soloader/ExternalSoMapping.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * 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.soloader; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Similar to {@link MergedSoMapping}, but this interface allows extrenal libraries and map to + * provide their own mapping from Open Source. + */ +@ThreadSafe +interface ExternalSoMapping { + @Nullable + String mapLibName(String preMergedLibName); + + void invokeJniOnload(String preMergedLibName); +} diff --git a/java/com/facebook/soloader/SoLoader.java b/java/com/facebook/soloader/SoLoader.java index deb5c52..de20cf1 100644 --- a/java/com/facebook/soloader/SoLoader.java +++ b/java/com/facebook/soloader/SoLoader.java @@ -239,6 +239,12 @@ interface AppType { private static int sAppType = AppType.UNSET; + /** + * If provided during the init method, external libraries can provide their own implementation + * ExternalSoMapping. This is useful for apps that want to use SoMerging in OSS. + */ + @Nullable private static ExternalSoMapping externalSoMapping = null; + static { boolean shouldSystrace = false; try { @@ -313,6 +319,31 @@ public static void init(Context context, boolean nativeExopackage) { } } + /** + * 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. + * + *

This is used only by apps that use SoMerging in OSS, such as React Native apps. + * + * @param context application context + * @param flags Zero or more of the SOLOADER_* flags + * @param soFileLoader the custom {@link SoFileLoader}, you can implement your own loader + * @param externalSoMapping the custom {@link ExternalSoMapping} if the App is using SoMerging. + * @throws IOException IOException + */ + public static void init( + Context context, + int flags, + @Nullable SoFileLoader soFileLoader, + @Nullable ExternalSoMapping externalSoMapping) + throws IOException { + synchronized (SoLoader.class) { + SoLoader.externalSoMapping = externalSoMapping; + } + init(context, flags, soFileLoader); + } + /** * Determine whether to enable soloader. * @@ -745,7 +776,12 @@ public static SoSource[] cloneSoSources() { * @return the File object of the so file */ public static @Nullable File getSoFile(String shortName) { - String mergedLibName = MergedSoMapping.mapLibName(shortName); + String mergedLibName; + if (externalSoMapping != null) { + mergedLibName = externalSoMapping.mapLibName(shortName); + } else { + mergedLibName = MergedSoMapping.mapLibName(shortName); + } String soName = mergedLibName != null ? mergedLibName : shortName; String mappedName = System.mapLibraryName(soName); @@ -808,7 +844,12 @@ public static boolean loadLibrary(String shortName, int loadFlags) throws Unsati @SuppressLint({"CatchGeneralException", "EmptyCatchBlock"}) private static boolean loadLibraryOnAndroid(String shortName, int loadFlags) { @Nullable Throwable failure = null; - String mergedLibName = MergedSoMapping.mapLibName(shortName); + String mergedLibName; + if (externalSoMapping != null) { + mergedLibName = externalSoMapping.mapLibName(shortName); + } else { + mergedLibName = MergedSoMapping.mapLibName(shortName); + } String soName = mergedLibName != null ? mergedLibName : shortName; ObserverHolder.onLoadLibraryStart(shortName, mergedLibName, loadFlags); boolean wasLoaded = false; @@ -1057,7 +1098,7 @@ private static boolean loadLibraryBySoNameImpl( boolean wasAlreadyJniInvoked = !TextUtils.isEmpty(shortName) && sLoadedAndJniInvoked.contains(shortName); if (!wasAlreadyJniInvoked) { - if (SYSTRACE_LIBRARY_LOADING) { + if (SYSTRACE_LIBRARY_LOADING && externalSoMapping == null) { Api18TraceUtils.beginTraceSection("MergedSoMapping.invokeJniOnload[", shortName, "]"); } try { @@ -1067,7 +1108,11 @@ private static boolean loadLibraryBySoNameImpl( + shortName + ", which was merged into " + soName); - MergedSoMapping.invokeJniOnload(shortName); + if (externalSoMapping != null) { + externalSoMapping.invokeJniOnload(shortName); + } else { + MergedSoMapping.invokeJniOnload(shortName); + } sLoadedAndJniInvoked.add(shortName); } catch (UnsatisfiedLinkError e) { // If you are seeing this exception, first make sure your library sets @@ -1095,7 +1140,7 @@ private static boolean loadLibraryBySoNameImpl( + "'. See comment for details.", e); } finally { - if (SYSTRACE_LIBRARY_LOADING) { + if (SYSTRACE_LIBRARY_LOADING && externalSoMapping == null) { Api18TraceUtils.endSection(); } }