From 17b6163a261dfbe4b47c9a61de295208344b497d Mon Sep 17 00:00:00 2001 From: Al Sutton Date: Fri, 22 Jan 2021 08:25:24 -0800 Subject: [PATCH] Add synchronized block to protect against race condition (#69) Summary: Fixes: https://github.com/facebook/SoLoader/issues/60 As mentioned in issue https://github.com/facebook/SoLoader/issues/60 if the init method is called twice from two different threads it can result in a race condition where both threads receive false for `NativeLoader.isInitialized()`, but, when `NativeLoader.init()` is run for a second time it throws an exception. Adding a synchronized block here ensures that only one thread will be able to query the initialisation state and trigger the initialisation at a time. Pull Request resolved: https://github.com/facebook/SoLoader/pull/69 Reviewed By: oprisnik Differential Revision: D25973362 Pulled By: wizh fbshipit-source-id: d340bae2b8891c6f095a2560b37ded50cf20ab67 --- java/com/facebook/soloader/SoLoader.java | 4 +--- .../facebook/soloader/nativeloader/NativeLoader.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/java/com/facebook/soloader/SoLoader.java b/java/com/facebook/soloader/SoLoader.java index 66f5c23..c1c7837 100644 --- a/java/com/facebook/soloader/SoLoader.java +++ b/java/com/facebook/soloader/SoLoader.java @@ -205,9 +205,7 @@ public static void init(Context context, int flags, @Nullable SoFileLoader soFil isSystemApp = checkIfSystemApp(context, flags); initSoLoader(soFileLoader); initSoSources(context, flags, soFileLoader); - if (!NativeLoader.isInitialized()) { - NativeLoader.init(new NativeLoaderToSoLoaderDelegate()); - } + NativeLoader.initIfUninitialized(new NativeLoaderToSoLoaderDelegate()); } finally { StrictMode.setThreadPolicy(oldPolicy); } diff --git a/java/com/facebook/soloader/nativeloader/NativeLoader.java b/java/com/facebook/soloader/nativeloader/NativeLoader.java index f1f460d..535d87d 100644 --- a/java/com/facebook/soloader/nativeloader/NativeLoader.java +++ b/java/com/facebook/soloader/nativeloader/NativeLoader.java @@ -112,4 +112,15 @@ public static synchronized void init(NativeLoaderDelegate delegate) { public static synchronized boolean isInitialized() { return sDelegate != null; } + + /** + * Perform an initialization only if {@code NativeLoader} has not already been initialized. This + * protects against race conditions where isInitialized and init are called by multiple threads + * and both threads end up trying to perform an initialization + */ + public static synchronized void initIfUninitialized(NativeLoaderDelegate delegate) { + if (!isInitialized()) { + init(delegate); + } + } }