Skip to content

Commit

Permalink
Removing concept of MainDex/non-MainDex native
Browse files Browse the repository at this point in the history
With automatic registration being the default now, there is no need to
differentiate MainDex/non-MainDex as automatic registration is lazy
anyways.

Low-Coverage-Reason: Just a deletion of code
Bug: 1371542
Change-Id: I85cc1f72e71eb4b2ed36a06bd8b0a25a484ce3fe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4385433
Owners-Override: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Commit-Queue: Sam Maier <smaier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1124766}
  • Loading branch information
Sam Maier authored and Chromium LUCI CQ committed Mar 31, 2023
1 parent 3ec0b44 commit 126fae8
Show file tree
Hide file tree
Showing 43 changed files with 101 additions and 778 deletions.
21 changes: 0 additions & 21 deletions base/android/java/src/org/chromium/base/JNIUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
@MainDex
public class JNIUtils {
private static final String TAG = "JNIUtils";
private static Boolean sSelectiveJniRegistrationEnabled;
private static ClassLoader sJniClassLoader;

/**
Expand Down Expand Up @@ -51,26 +50,6 @@ public static void setClassLoader(ClassLoader classLoader) {
sJniClassLoader = classLoader;
}

/**
* @return whether or not the current process supports selective JNI registration.
*/
@CalledByNative
public static boolean isSelectiveJniRegistrationEnabled() {
if (sSelectiveJniRegistrationEnabled == null) {
sSelectiveJniRegistrationEnabled = false;
}
return sSelectiveJniRegistrationEnabled;
}

/**
* Allow this process to selectively perform JNI registration. This must be called before
* loading native libraries or it will have no effect.
*/
public static void enableSelectiveJniRegistration() {
assert sSelectiveJniRegistrationEnabled == null;
sSelectiveJniRegistrationEnabled = true;
}

/**
* Helper to convert from java maps to two arrays for JNI.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,20 @@ public class NativeLibraryLoadedStatus {
* Interface for querying native method availability.
*/
public interface NativeLibraryLoadedStatusProvider {
boolean areMainDexNativeMethodsReady();
boolean areNativeMethodsReady();
}

private static NativeLibraryLoadedStatusProvider sProvider;

public static void checkLoaded(boolean isMainDex) {
public static void checkLoaded() {
// Necessary to make sure all of these calls are stripped in release builds.
if (!BuildConfig.ENABLE_ASSERTS) return;

if (sProvider == null) return;

boolean nativeMethodsReady = isMainDex ? sProvider.areMainDexNativeMethodsReady()
: sProvider.areNativeMethodsReady();
if (!nativeMethodsReady) {
throw new JniException(String.format(
"Native method called before the native library was ready (isMainDex=%b).",
isMainDex));
if (!sProvider.areNativeMethodsReady()) {
throw new JniException(
String.format("Native method called before the native library was ready."));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.chromium.base.BaseSwitches;
import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.JNIUtils;
import org.chromium.base.Log;
import org.chromium.base.NativeLibraryLoadedStatus;
import org.chromium.base.NativeLibraryLoadedStatus.NativeLibraryLoadedStatusProvider;
Expand Down Expand Up @@ -82,7 +81,7 @@ public class LibraryLoader {

private static boolean sBrowserStartupBlockedForTesting;

// Helps mInitializedForTesting and mLoadStateForTesting to be removed by R8.
// Helps mInitializedForTesting and mLoadedForTesting to be removed by R8.
private static boolean sEnableStateForTesting;

// One-way switch becomes true when the libraries are initialized (by calling
Expand All @@ -96,20 +95,12 @@ public class LibraryLoader {
// synchronization.
private boolean mFallbackToSystemLinker;

// State that only transitions one-way from 0->1->2. Volatile for the same reasons as
// mInitialized.
@IntDef({LoadState.NOT_LOADED, LoadState.MAIN_DEX_LOADED, LoadState.LOADED})
@Retention(RetentionPolicy.SOURCE)
private @interface LoadState {
int NOT_LOADED = 0;
int MAIN_DEX_LOADED = 1;
int LOADED = 2;
}
private volatile @LoadState int mLoadState;
// State that only transitions from false->true. Volatile for the same reasons as mInitialized.
private volatile boolean mLoaded;

// Tracks mLoadState, but can be reset to NOT_LOADED between tests to ensure that each test that
// Tracks mLoaded, but can be reset to NOT_LOADED between tests to ensure that each test that
// requires native explicitly loads it.
private @LoadState int mLoadStateForTesting;
private boolean mLoadedForTesting;

// Tracks mInitialized, but can be reset to false between tests to ensure that each test that
// requires native explicitly loads it.
Expand All @@ -123,10 +114,6 @@ public class LibraryLoader {
// Avoids locking: should be initialized very early.
private @LibraryProcessType int mLibraryProcessType;

// Makes sure non-Main Dex initialization happens only once. Does not use any class members
// except the volatile |mLoadState|.
private final Object mNonMainDexLock = new Object();

// Mediates all communication between Linker instances in different processes.
private final MultiProcessMediator mMediator = new MultiProcessMediator();

Expand All @@ -145,7 +132,7 @@ public class LibraryLoader {
@GuardedBy("mLock")
private boolean mLibraryPreloaderCalled;

// Similar to |mLoadState| but is limited case of being loaded in app zygote.
// Similar to |mLoaded| but is limited case of being loaded in app zygote.
// This is exposed to clients.
@GuardedBy("mLock")
private boolean mLoadedByZygote;
Expand Down Expand Up @@ -421,11 +408,6 @@ protected LibraryLoader() {
}
if (BuildConfig.ENABLE_ASSERTS) {
NativeLibraryLoadedStatus.setProvider(new NativeLibraryLoadedStatusProvider() {
@Override
public boolean areMainDexNativeMethodsReady() {
return isMainDexLoaded();
}

@Override
public boolean areNativeMethodsReady() {
return isLoaded();
Expand Down Expand Up @@ -463,7 +445,7 @@ public void setLibraryProcessType(@LibraryProcessType int type) {
public void setNativeLibraryPreloader(NativeLibraryPreloader loader) {
synchronized (mLock) {
assert mLibraryPreloader == null;
assert mLoadState == LoadState.NOT_LOADED;
assert !mLoaded;
mLibraryPreloader = loader;
}
}
Expand Down Expand Up @@ -529,25 +511,9 @@ public boolean isLoadedByZygote() {
*/
public void ensureInitialized() {
if (isInitialized()) return;
ensureMainDexInitialized();
loadNonMainDex();
}

/**
* This method blocks until the native library is initialized, and the Main Dex is loaded
* (MainDex JNI is registered).
*
* You should use this if you would like to use isolated parts of the native library that don't
* depend on content initialization, and only use MainDex classes with JNI.
*
* However, you should be careful not to call this too early in startup on the UI thread, or you
* may significantly increase the time to first draw.
*/
public void ensureMainDexInitialized() {
synchronized (mLock) {
if (DEBUG) logLinkerUsed();
loadMainDexAlreadyLocked(
ContextUtils.getApplicationContext().getApplicationInfo(), false);
loadAlreadyLocked(ContextUtils.getApplicationContext().getApplicationInfo(), false);
initializeAlreadyLocked();
}
}
Expand Down Expand Up @@ -594,13 +560,7 @@ private void preloadAlreadyLocked(String packageName, boolean inZygote) {
@Deprecated
@VisibleForTesting
public boolean isLoaded() {
return mLoadState == LoadState.LOADED
&& (!sEnableStateForTesting || mLoadStateForTesting == LoadState.LOADED);
}

private boolean isMainDexLoaded() {
return mLoadState >= LoadState.MAIN_DEX_LOADED
&& (!sEnableStateForTesting || mLoadStateForTesting >= LoadState.MAIN_DEX_LOADED);
return mLoaded && (!sEnableStateForTesting || mLoadedForTesting);
}

/**
Expand All @@ -627,7 +587,7 @@ public void loadNow() {
* Causes LibraryLoader to pretend that native libraries have not yet been initialized.
*/
public void resetForTesting() {
mLoadStateForTesting = LoadState.NOT_LOADED;
mLoadedForTesting = false;
mInitializedForTesting = false;
sEnableStateForTesting = true;
}
Expand All @@ -641,20 +601,17 @@ public void resetForTesting() {
*/
public void loadNowOverrideApplicationContext(Context appContext) {
synchronized (mLock) {
if (mLoadState != LoadState.NOT_LOADED
&& appContext != ContextUtils.getApplicationContext()) {
if (mLoaded && appContext != ContextUtils.getApplicationContext()) {
throw new IllegalStateException("Attempt to load again from alternate context.");
}
loadMainDexAlreadyLocked(appContext.getApplicationInfo(), /* inZygote= */ false);
loadAlreadyLocked(appContext.getApplicationInfo(), /* inZygote= */ false);
}
loadNonMainDex();
}

public void loadNowInZygote(ApplicationInfo appInfo) {
synchronized (mLock) {
assert mLoadState == LoadState.NOT_LOADED;
loadMainDexAlreadyLocked(appInfo, /* inZygote= */ true);
loadNonMainDex();
assert !mLoaded;
loadAlreadyLocked(appInfo, /* inZygote= */ true);
mLoadedByZygote = true;
}
}
Expand Down Expand Up @@ -759,14 +716,14 @@ private void loadWithSystemLinkerAlreadyLocked(ApplicationInfo appInfo, boolean
// triggering JNI_OnLoad in native code.
@GuardedBy("mLock")
@VisibleForTesting
protected void loadMainDexAlreadyLocked(ApplicationInfo appInfo, boolean inZygote) {
if (mLoadState >= LoadState.MAIN_DEX_LOADED) {
if (sEnableStateForTesting && mLoadStateForTesting == LoadState.NOT_LOADED) {
mLoadStateForTesting = LoadState.MAIN_DEX_LOADED;
protected void loadAlreadyLocked(ApplicationInfo appInfo, boolean inZygote) {
if (mLoaded) {
if (sEnableStateForTesting && !mLoadedForTesting) {
mLoadedForTesting = true;
}
return;
}
try (TraceEvent te = TraceEvent.scoped("LibraryLoader.loadMainDexAlreadyLocked")) {
try (TraceEvent te = TraceEvent.scoped("LibraryLoader.loadAlreadyLocked")) {
assert !mInitialized;
assert mLibraryProcessType != LibraryProcessType.PROCESS_UNINITIALIZED || inZygote;

Expand All @@ -788,9 +745,9 @@ protected void loadMainDexAlreadyLocked(ApplicationInfo appInfo, boolean inZygot
long loadTimeMs = uptimeTimer.getElapsedMillis();

if (DEBUG) Log.i(TAG, "Time to load native libraries: %d ms", loadTimeMs);
mLoadState = LoadState.MAIN_DEX_LOADED;
mLoaded = true;
if (sEnableStateForTesting) {
mLoadStateForTesting = LoadState.MAIN_DEX_LOADED;
mLoadedForTesting = true;
}

getMediator().recordLoadTimeHistogram(loadTimeMs);
Expand All @@ -800,30 +757,6 @@ protected void loadMainDexAlreadyLocked(ApplicationInfo appInfo, boolean inZygot
}
}

@VisibleForTesting
protected void loadNonMainDex() {
if (mLoadState == LoadState.LOADED) {
if (sEnableStateForTesting) {
mLoadStateForTesting = LoadState.LOADED;
}
return;
}
synchronized (mNonMainDexLock) {
assert mLoadState != LoadState.NOT_LOADED;
if (mLoadState == LoadState.LOADED) return;
try (TraceEvent te = TraceEvent.scoped("LibraryLoader.loadNonMainDex")) {
if (!JNIUtils.isSelectiveJniRegistrationEnabled()) {
// On M+ the native symbols are exported, and registering natives seems fast.
LibraryLoaderJni.get().registerNonMainDexJni();
}
mLoadState = LoadState.LOADED;
if (sEnableStateForTesting) {
mLoadStateForTesting = LoadState.LOADED;
}
}
}
}

// The WebView requires the Command Line to be switched over before
// initialization is done. This is okay in the WebView's case since the
// JNI is already loaded by this point.
Expand All @@ -838,7 +771,7 @@ public void switchCommandLineForWebView() {
// switch the Java CommandLine will delegate all calls the native CommandLine).
@GuardedBy("mLock")
private void ensureCommandLineSwitchedAlreadyLocked() {
assert isMainDexLoaded();
assert isLoaded();
if (mCommandLineSwitched) {
return;
}
Expand Down Expand Up @@ -901,10 +834,8 @@ private void initializeAlreadyLocked() {
// From now on, keep tracing in sync with native.
TraceEvent.onNativeTracingReady();

// From this point on, native code is ready to use, but non-MainDex JNI may not yet have
// been registered. Check isInitialized() to be sure that initialization is fully complete.
// Note that this flag can be accessed asynchronously, so any initialization
// must be performed before.
// From this point on, native code is ready to use. Note that this flag can be accessed
// asynchronously, so any initialization must be performed before.
mInitialized = true;
if (sEnableStateForTesting) {
mInitializedForTesting = true;
Expand Down Expand Up @@ -957,11 +888,11 @@ public static void setEnvForNative() {
*/
protected static void setLibrariesLoadedForNativeTests() {
LibraryLoader self = getInstance();
self.mLoadState = LoadState.LOADED;
self.mLoaded = true;
self.mInitialized = true;
if (sEnableStateForTesting) {
self.mInitializedForTesting = true;
self.mLoadStateForTesting = LoadState.LOADED;
self.mLoadedForTesting = true;
}
}

Expand All @@ -979,9 +910,5 @@ interface Natives {
// Performs auxiliary initialization useful right after the native library load. Returns
// true on success and false on failure.
boolean libraryLoaded(@LibraryProcessType int processType);

// Registers JNI for non-main processes. For details see android_native_libraries.md,
// android_dynamic_feature_modules.md and jni_generator/README.md
void registerNonMainDexJni();
}
}
Loading

0 comments on commit 126fae8

Please sign in to comment.