chenxiaolong / RSAF

An Android Storage Access Framework document provider for rclone
GNU General Public License v3.0
211 stars 6 forks source link

three issues + one feature request #93

Open dermitza opened 3 hours ago

dermitza commented 3 hours ago

Hello,

thanks a lot for your efforts, its a quite nice app after a first look. Below are three issues (one important possibly) and a feature request.

Device: G8441, Android version 9, API 28

(Issue) App crashes when enabling require authentication

After enabling "require authentication", app crashes on open, clearing data is necessary (to clear the condition) in order to restore app to functional. ADB/logcat shows the following:

' --------- beginning of crash 2024-10-25 23:03:01.899 29781-29781/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.chiller3.rsaf, PID: 29781 java.lang.RuntimeException: Unable to resume activity {com.chiller3.rsaf/com.chiller3.rsaf.SettingsActivity}: java.lang.IllegalArgumentException: Authenticator combination is unsupported on API 28: BIOMETRIC_STRONG | DEVICE_CREDENTIAL at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3796) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828) at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1814) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:280) at android.app.ActivityThread.main(ActivityThread.java:6706) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) Caused by: java.lang.IllegalArgumentException: Authenticator combination is unsupported on API 28: BIOMETRIC_STRONG | DEVICE_CREDENTIAL at com.chiller3.rsaf.SettingsFragment.onResume(Unknown Source:489) at androidx.fragment.app.FragmentStateManager.resume(Unknown Source:148) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(Unknown Source:58) at androidx.fragment.app.FragmentManagerImpl.moveToState(Unknown Source:61) at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(Unknown Source:35) at androidx.appcompat.app.AppCompatActivity.onPostResume$androidx$fragment$app$FragmentActivity(Unknown Source:28) at androidx.appcompat.app.AppCompatActivity.onPostResume(Unknown Source:0) at android.app.Activity.performResume(Activity.java:7317) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3788) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)  at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)  at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1814)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loop(Looper.java:280)  at android.app.ActivityThread.main(ActivityThread.java:6706)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)  2024-10-25 23:03:01.906 29781-29781/? E/MainApplication: Saving logcat to /storage/emulated/0/Android/data/com.chiller3.rsaf/files/crash.log due to uncaught exception in Thread[main,5,main] java.lang.RuntimeException: Unable to resume activity {com.chiller3.rsaf/com.chiller3.rsaf.SettingsActivity}: java.lang.IllegalArgumentException: Authenticator combination is unsupported on API 28: BIOMETRIC_STRONG | DEVICE_CREDENTIAL at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3796) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828) at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1814) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:280) at android.app.ActivityThread.main(ActivityThread.java:6706) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) Caused by: java.lang.IllegalArgumentException: Authenticator combination is unsupported on API 28: BIOMETRIC_STRONG | DEVICE_CREDENTIAL at com.chiller3.rsaf.SettingsFragment.onResume(Unknown Source:489) at androidx.fragment.app.FragmentStateManager.resume(Unknown Source:148) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(Unknown Source:58) at androidx.fragment.app.FragmentManagerImpl.moveToState(Unknown Source:61) at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(Unknown Source:35) at androidx.appcompat.app.AppCompatActivity.onPostResume$androidx$fragment$app$FragmentActivity(Unknown Source:28) at androidx.appcompat.app.AppCompatActivity.onPostResume(Unknown Source:0) at android.app.Activity.performResume(Activity.java:7317) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3788) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)  at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)  at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1814)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loop(Looper.java:280)  at android.app.ActivityThread.main(ActivityThread.java:6706)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) '

As i understand it is just an unsupported API call for this Android version, maybe a catch around the exception would mitigate this. Further, as I am not interested in the biometric aspect of authentication but rather the PIN functionality, maybe there is an easy conditional to split the options for older API versions?

(Issue) App cannot open any file on filesystem, other than files it has created

If i try to import a config file from the local filesystem, all (most) files including the config file are greyed out and non-selectable.

image

Workaround

If I then however (2) export a blank config file from the app (works, no errors), (2) edit the config file externally and adding information and (3) attempt to import it, that particular file is still selectable and I am able to import it. This looks to be some obscure FS permission issue (?) with no relevant logcat information (even when verbose mode is selected)

logcat info upon pressing "import configuration" are not relevant (at least upon first inspection):

--------- beginning of main 2024-10-25 23:22:23.173 924-924/? D/SDM: DisplayBase::BuildLayerStackStats: LayerStack layer_count: 4, app_layer_count: 3, gpu_target_index: 3, display type: 0 2024-10-25 23:22:23.176 30824-30824/? W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@f61f959 2024-10-25 23:22:23.173 927-927/? W/memtrack@1.0-se: type=1400 audit(0.0:468026): avc: denied { search } for name="proc" dev="debugfs" ino=11572 scontext=u:r:hal_memtrack_default:s0 tcontext=u:object_r:qti_debugfs:s0 tclass=dir permissive=0 ppid=1 pcomm="init" pgid=1 pgcomm="init" 2024-10-25 23:22:23.184 1717-1782/? I/DisplayBooster: DisplayBoosterService: CABC is not supported in this model 2024-10-25 23:22:23.186 3611-3657/? I/android_os_HwBinder: HwBinder: Starting thread pool for default::vendor.somc.hardware.swiqi@1.0::IHidlSwiqi 2024-10-25 23:22:23.187 3611-3657/? I/android_os_HwBinder: HwBinder: Starting thread pool for default::vendor.somc.hardware.swiqi@1.0::IHidlSwiqi 2024-10-25 23:22:23.205 924-924/? D/SDM: DisplayBase::BuildLayerStackStats: LayerStack layer_count: 4, app_layer_count: 3, gpu_target_index: 3, display type: 0 2024-10-25 23:22:23.211 1717-1741/? I/InputDispatcher: Focus entered window: Window{9750988 u0 com.android.documentsui/com.android.documentsui.picker.PickActivity} 2024-10-25 23:22:23.222 924-924/? D/SDM: DisplayBase::BuildLayerStackStats: LayerStack layer_count: 4, app_layer_count: 3, gpu_target_index: 3, display type: 0 2024-10-25 23:22:23.253 3528-3528/? I/LatinIME: onFinishInput 2024-10-25 23:22:23.267 1717-1803/? I/ActivityManager: Displayed com.android.documentsui/.picker.PickActivity: +92ms 2024-10-25 23:22:23.289 924-924/? D/SDM: DisplayBase::BuildLayerStackStats: LayerStack layer_count: 5, app_layer_count: 4, gpu_target_index: 4, display type: 0 2024-10-25 23:22:23.524 924-924/? I/chatty: uid=1000(system) composer@2.1-se identical 14 lines 2024-10-25 23:22:23.541 924-924/? D/SDM: DisplayBase::BuildLayerStackStats: LayerStack layer_count: 5, app_layer_count: 4, gpu_target_index: 4, display type: 0 2024-10-25 23:22:23.550 1717-1803/? I/Timeline: Timeline: Activity_windows_visible id: ActivityRecord{e0830f u0 com.android.documentsui/.picker.PickActivity t2021} time:155119498 diff:375 start:lukewarm|cch-empty batt:76|2 mw:off|358 mem:1577056|0|56|2|22 cpu:[1,1,1,1,1,1,1,1],[1900,2457] 2024-10-25 23:22:23.558 924-924/? D/SDM: DisplayBase::BuildLayerStackStats: LayerStack layer_count: 4, app_layer_count: 3, gpu_target_index: 3, display type: 0 2024-10-25 23:22:23.580 1717-1782/? I/DisplayBooster: DisplayBoosterService: CABC is not supported in this model 2024-10-25 23:22:23.583 3611-3634/? I/android_os_HwBinder: HwBinder: Starting thread pool for default::vendor.somc.hardware.swiqi@1.0::IHidlSwiqi

logcat info upon pressing a greyed out file is a drawing update, also not relevant:

2024-10-25 23:14:40.054 924-924/? D/SDM: DisplayBase::BuildLayerStackStats: LayerStack layer_count: 4, app_layer_count: 3, gpu_target_index: 3, display type: 0

I also checked whether there are any fs permissions missing but I do not have any available selectable permissions at all for the app.

(Minor issue) App window overextends under bottom navigation bar

image image

This is not as important, the app borders do not snap to within the active display area and overextend under the bottom navigation bar (maybe the minSize sets are too large - given i am using a small display).

(Feature request) Selectable theme

A dark (selectable) theme would be nice but not really of any importance.

Again thanks a lot for your efforts and a nice app :)

chenxiaolong commented 3 hours ago

Thanks for the detailed report and glad you like the app!

(Issue) App crashes when enabling require authentication

Hmm, I wasn't aware of this. It looks like both BIOMETRIC_STRONG or DEVICE_CREDENTIAL are only supported since API 30. I'll have to check to see if this functionality can be supported in API 28. I don't have an Android 9 device for testing--do you know if other third party apps support biometric auth?

(Issue) App cannot open any file on filesystem, other than files it has created

What were the exact filenames of the files that could and could not be selected for importing? I think this might be caused by the file extension. There's a chance it might only be allowing you to select files where the extension is unrecognized by Android. This should be an easy fix once I know what's going on.

(Minor issue) App window overextends under bottom navigation bar

It is expected for the list to extend into the navigation bar, but there is supposed to be extra padding after scrolling to the very bottom. This one might be a bug in Android's compatibility libraries. "edge to edge" mode is now mandatory in Android 15, but the Google's compatibility layer is meant to make it work properly in previous versions of Android too. I'll see if I can find a workaround for this.

chenxiaolong commented 3 hours ago

(Feature request) Selectable theme

The app should already follow the system dark/light theme mode. (Or are you asking for a new option to force it to be always light or always dark?)

dermitza commented 2 hours ago

Thanks a lot for the (very!) prompt reply.

Thanks for the detailed report and glad you like the app!

(Issue) App crashes when enabling require authentication

Hmm, I wasn't aware of this. It looks like both BIOMETRIC_STRONG or DEVICE_CREDENTIAL are only supported since API 30. I'll have to check to see if this functionality can be supported in API 28. I don't have an Android 9 device for testing--do you know if other third party apps support biometric auth?

I quickly checked functionality with KeePassDX, it has seperated biometrics and device credentials (two seperate toggle bars), biometric enabling worked fine (did not test further with a fingerprint), device credential as well, prompting me to enter device pin/password/gesture (worked fine, showing pin/password/gesture menu).

The fix might be as easy as replacing (line 220 in PreferenceBaseActivity.kt)

   val promptInfo = BiometricPrompt.PromptInfo.Builder()
       .setAllowedAuthenticators(Authenticators.BIOMETRIC_STRONG or Authenticators.DEVICE_CREDENTIAL)
       .setTitle(getString(R.string.biometric_title))
       .build()

with

   val promptInfo = createPromptInfo()
       if (BiometricManager.from(context)
           .canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
           biometricPrompt.authenticate(promptInfo, cryptoObject)
       } else {
           // unsupported prompt perhaps
       }

as detailed here and here. It seems as though the above call is API agnostic (everything done under the hood) for down to API 23 (?). For instantiating a crypto object (maybe i missed it), possibly relevant post for that here.

(Issue) App cannot open any file on filesystem, other than files it has created

What were the exact filenames of the files that could and could not be selected for importing? I think this might be caused by the file extension. There's a chance it might only be allowing you to select files where the extension is unrecognized by Android. This should be an easy fix once I know what's going on.

Im not sure if it is file extension dependent. The pre-existing selectable files i saw had .zdjBDp and .ini extensions.

Duplicating (in total commander) any file created by the app is also openable, irrespective of extension (tried multiple extensions). Copying a .conf file into android (from a PC) is not openable. No discernible differences between files created by RSAF or externally according to total commander (both show uid 0, gid 9997, -rw-rw----).

image image image

(Minor issue) App window overextends under bottom navigation bar

It is expected for the list to extend into the navigation bar, but there is supposed to be extra padding after scrolling to the very bottom. This one might be a bug in Android's compatibility libraries. "edge to edge" mode is now mandatory in Android 15, but the Google's compatibility layer is meant to make it work properly in previous versions of Android too. I'll see if I can find a workaround for this.

No worries about this one, minor enough i think.

The app should already follow the system dark/light theme mode. (Or are you asking for a new option to force it to be always light or always dark?)

Yep, but as I mentioned, not really critical, thanks a lot again.

chenxiaolong commented 2 hours ago

Thanks for the hint about KeePassDX. I'll check that out and see how they handle device credential auth. If it's too painful to implement, I'll just stick with biometric auth only for older Android versions.

Im not sure if it is file extension dependent. The pre-existing selectable files i saw had .zdjBDp and .ini extensions.

Duplicating (in total commander) any file created by the app is also openable, irrespective of extension (tried multiple extensions). Copying a .conf file into android (from a PC) is not openable. No discernible differences between files created by RSAF or externally according to total commander (both show uid 0, gid 9997, -rw-rw----).

Interesting. The way it's set up right now is that RSAF asks Android to allow picking any file with the text/plain or application/octet-stream MIME types. On later Android versions, this is based entirely on the file extension (txt/text/pot/brf/srt for text/plain and bin/deploy/msu/msp + all unrecognized extensions for application/octet-stream).

I think it probably makes the most sense to just remove the filter. It doesn't seem all that useful anyway.

chenxiaolong commented 2 hours ago

Oh, one quick question about the file selection: when you selected the files, was it from the hamburger menu -> "Downloads" section of the file picker or from hamburger menu -> (Phone name) -> Downloads folder?

(The reason I ask is because they are not the same and the files go through two completely different components in Android that may not treat file types the same way.)

dermitza commented 2 hours ago

Oh, one quick question about the file selection: when you selected the files, was it from the hamburger menu -> "Downloads" section of the file picker or from hamburger menu -> (Phone name) -> Downloads folder?

(The reason I ask is because they are not the same and the files go through two completely different components in Android that may not treat file types the same way.)

Both choices exhibit the same behaviour it seems.

chenxiaolong commented 1 hour ago

I wonder if that behavior is Sony-specific. I can't reproduce it with a Samsung Galaxy Note 9 running Android 9. Anyway, I'll just remove the filter.

chenxiaolong commented 1 hour ago

I was able to get biometric + device credential auth working on Android 9 (#94). It was a lot easier than I initially thought.

dermitza commented 1 hour ago

I can test run a test apk if you'd like (i'd compile the test branch and do it myself but the android dev environment i have around atm is quite outdated - was trying to resolve dependencies for the past half hour lol)

dermitza commented 1 hour ago

I wonder if that behavior is Sony-specific. I can't reproduce it with a Samsung Galaxy Note 9 running Android 9. Anyway, I'll just remove the filter.

is there a possibilty of a conflict with different content providers? But im not seeing anything in logcat tbh. Would there be a way to debug this further?