facebook / flipper

A desktop debugging platform for mobile developers.
https://fbflipper.com/
MIT License
13.36k stars 955 forks source link

Crash on SoLoader.init() Samsung Galaxy S9 Only #2213

Open joel-kenny opened 3 years ago

joel-kenny commented 3 years ago

🐛 Bug Report

This only happens on one phone, which happens to be a Samsung Galaxy S9 that previously had no problem. It started happening today and seems to be related to that specific phone. Old app versions that worked before no longer work. It appears that the app no longer has permission to access the lock file. Tried giving it permission to write external storage but that had no effect.

FATAL EXCEPTION: main
Process: <application_id>, PID: 2497
java.lang.RuntimeException: Unable to create application <application_class_name>: java.lang.RuntimeException: java.io.FileNotFoundException: /data/user/0/<application_id>/lib-main/dso_lock: open failed: EACCES (Permission denied)
       at android.app.ActivityThread.handleMakeApplication(ActivityThread.java:7150)
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7095)
       at android.app.ActivityThread.access$1700(ActivityThread.java:273)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2105)
       at android.os.Handler.dispatchMessage(Handler.java:107)
       at android.os.Looper.loop(Looper.java:237)
       at android.app.ActivityThread.main(ActivityThread.java:8125)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
Caused by: java.lang.RuntimeException: java.io.FileNotFoundException: /data/user/0/<application_id>/lib-main/dso_lock: open failed: EACCES (Permission denied)
       at com.facebook.soloader.SoLoader.init(SoLoader.java:219)
       at com.<app_package>.utils.FlipperHelper.enableFlipper(FlipperHelper.kt:19)
       at com.<application_class_name>.onCreate(AvaApp.kt:100)
       at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1190)
       at android.app.ActivityThread.handleMakeApplication(ActivityThread.java:7145)
       ... 9 more
Caused by: java.io.FileNotFoundException: /data/user/0/<application_id>/lib-main/dso_lock: open failed: EACCES (Permission denied)
       at libcore.io.IoBridge.open(IoBridge.java:496)
       at java.io.FileOutputStream.<init>(FileOutputStream.java:235)
       at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
       at com.facebook.soloader.FileLocker.<init>(FileLocker.java:36)
       at com.facebook.soloader.FileLocker.lock(FileLocker.java:32)
       at com.facebook.soloader.UnpackingSoSource.prepare(UnpackingSoSource.java:430)
       at com.facebook.soloader.SoLoader.initSoSources(SoLoader.java:327)
       at com.facebook.soloader.SoLoader.init(SoLoader.java:207)
       at com.facebook.soloader.SoLoader.init(SoLoader.java:189)
       at com.facebook.soloader.SoLoader.init(SoLoader.java:217)
       ... 13 more
Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
       at libcore.io.Linux.open(Native Method)
       at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
       at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
       at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
       at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:8002)
       at libcore.io.IoBridge.open(IoBridge.java:482)

To Reproduce

Start the app. It crashes immediately.

Environment

Android 10 Samsung Galaxy S9

commonsguy commented 3 years ago

Teammates have also run into this on a Pixel 4 and a Pixel 3 XL, so it is not specific to the Galaxy S9. We have not been able to isolate steps to reproduce the problem. There is some evidence that it is tied to Android's backup system -- one teammate got past this by setting allowBackup to false.

joel-kenny commented 3 years ago

@commonsguy that makes sense. Somehow the application does not have permission to access the lock file. Thanks for the tip! I'll see if it works.

zakrodionov commented 3 years ago

Same error on v0.91.1 Poco X3

rodinhatokay commented 3 years ago

I'm having this issue with OnePlus 8T

mweststrate commented 3 years ago

We cannot really debug this from just a stack trace. I'd recommend to try running the flipper sample applications as can be found in this repo, and work from there.

yifeifiona commented 3 years ago

Same on Samsung Galaxy S9+

javglex commented 3 years ago

A few things that helped out my team and I: As a temporary solution clearing our app cache would quickly get Flipper working again. For a while at least. For a more permanent fix see below.

Our crashes happened because our _dsolock file would often get locked up by the automatic backup system. Throwing the same fatal error as the OP.

We can exclude the folder where the _dsolock file is located from the automatic backup system by creating backup rule sets.

Example

backup_rules.xml

<full-backup-content>
    <exclude domain="root" path="./data/user/0/co.yourapp.android.debug/lib-main/" />
    <exclude domain="root" path="./data/data/co.yourapp.android.debug/lib-main/" />
</full-backup-content>

Add this file to your debug res/xml directory. Make sure it's referenced in your AndroidManifest.xml file under the application tag

    <application
        android:fullBackupContent="@xml/backup_rules">

This should prevent the system from inadvertently locking up the _dsolock file.

Another thing we added to cover any other contingencies is to grant permissions to the folder were the _dsolock file is located

Example

Before calling SoLoader.init()

// in case read/write permissions are somehow still revoked by backup system, attempt to restore them here
try {
    File("${context.dataDir}/lib-main").setWritable(true, true)
    File("${context.dataDir}/lib-main").setReadable(true, true)
} catch (e: Exception) {
    Timber.e("Exception trying to apply permissions: ${e.localizedMessage}")
}

This should grant the necessary permissions and prevent the crash.

Hope this helps. Thanks @yuesaka-m for suggesting to post the fix, and @commonsguy for pointing me towards the right rabbithole

nes123 commented 3 years ago

Get some errors:

error: cannot find symbol File("${context.dataDir}/lib-main").setWritable(true, true);

although i did add import java.io.File;

any ideas?

yuesaka-m commented 3 years ago

@nes123

Get some errors:

error: cannot find symbol File("${context.dataDir}/lib-main").setWritable(true, true);

although i did add import java.io.File;

any ideas?

Is your file a java file? @javglex 's solution is in Kotlin (and also there's a Timber dependency, which you could replace with a regular Android Log) so it may just be that you need to alter it to:

 new File("${context.dataDir}/lib-main").setWritable(true, true);
jamsch commented 3 years ago

Would this be correct for React Native? Not much of an Android developer.

// MainApplication.java
import java.io.File;
import android.util.Log;

public class MainApplication extends Application implements ReactApplication {
    // ...
    @Override
    public void onCreate() {
      super.onCreate();
      Context applicationContext = getApplicationContext();
      try {
          String dataDir = applicationContext.getApplicationInfo().dataDir;
          File libMainDirectory = new File(dataDir + "/lib-main");
          libMainDirectory.setWritable(true, true);
          libMainDirectory.setReadable(true, true);
      } catch (Exception e) {
          Log.e("MainApplication", "Error setting permissions on data dir", e);
      }
      SoLoader.init(this, /* native exopackage */ false);
      // initialize Flipper, etc
    }
}    
yuesaka-m commented 3 years ago

@jamsch If it compiles and does not give you the crash on SoLoader.init when it does otherwise, I'd say it's more "correct" than it was before! The only thing I noticed is that you're using applicationContext.getApplicationInfo().dataDir to get the data directory, which if we're doing a more explicit Kotlin -> Java conversion, it'd be just applicationContext.getDataDir() or just getDataDir() (since your code is already running in the Application class, which is a subclass of Context already). It's entirely possible that all of these things point to the same String though.

@nes123 I was hasty with my Kotlin -> Java conversion in my previous comment. I haven't tested it beyond the fact that Android Studio does not give a compiler error anymore, but here's the Kotlin code converted to Java. I totally forgot Java doesn't have the same String interpolation syntax as Kotlin.

        try {
            String libMainPath = String.format("%s/lib-main", context.getDataDir());
            new File(libMainPath).setWritable(true, true);
            new File(libMainPath).setReadable(true, true);
        } catch (Exception e) {
            Log.e("TAG", "Exception trying to apply permissions: " + e.getLocalizedMessage());
        }

        SoLoader.init(context, false);
jamsch commented 3 years ago

Update for React Native users: It seems that React Native (ReactActivity) calls SoLoader as well. So you'll likely need to set the file permissions before calling super.onCreate();

https://github.com/facebook/react-native/blob/ce74aa4ed335d4c36ce722d47937b582045e05c4/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java#L398-L407

Caused by: java.io.FileNotFoundException: 
  at libcore.io.IoBridge.open (IoBridge.java:492)
  at java.io.FileOutputStream.<init> (FileOutputStream.java:236)
  at java.io.FileOutputStream.<init> (FileOutputStream.java:186)
  at com.facebook.soloader.FileLocker.<init> (FileLocker.java:36)
  at com.facebook.soloader.FileLocker.lock (FileLocker.java:32)
  at com.facebook.soloader.UnpackingSoSource.prepare (UnpackingSoSource.java:430)
  at com.facebook.soloader.SoLoader.initSoSources (SoLoader.java:327)
  at com.facebook.soloader.SoLoader.init (SoLoader.java:207)
  at com.facebook.soloader.SoLoader.init (SoLoader.java:189)
  at com.facebook.soloader.SoLoader.init (SoLoader.java:217)
  at com.facebook.react.ReactInstanceManager.initializeSoLoaderIfNecessary (ReactInstanceManager.java:360)
  at com.facebook.react.ReactInstanceManagerBuilder.getDefaultJSExecutorFactory (ReactInstanceManagerBuilder.java:296)
  at com.facebook.react.ReactInstanceManagerBuilder.build (ReactInstanceManagerBuilder.java:270)
  at com.facebook.react.ReactNativeHost.createReactInstanceManager (ReactNativeHost.java:87)
  at com.facebook.react.ReactNativeHost.getReactInstanceManager (ReactNativeHost.java:39)
  at com.facebook.react.ReactDelegate.loadApp (ReactDelegate.java:104)
  at com.facebook.react.ReactActivityDelegate.loadApp (ReactActivityDelegate.java:90)
  at com.facebook.react.ReactActivityDelegate.onCreate (ReactActivityDelegate.java:85)
  at com.facebook.react.ReactActivity.onCreate (ReactActivity.java:45)
  at com.example.app.MainActivity.onCreate (MainActivity.java:28)
aman32767 commented 2 years ago

In our case, the build version code is causing the issue.

Its was sorted till 407 but after that 408, 409 .. are causing crash.

We are building version code for variant releases at run time which is crossing some kind of limit.

Will update further in this group.

logic we are using for assigning version number:

  applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
            def versionCodes = ["armeabi-v7a":1, "x86":2, "arm64-v8a": 3,"x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
            }
        }
    }

Edit : setting allowBackup to false helped us. figuring out why version number came in picture.