woocommerce / woocommerce-android

WooCommerce Android app
https://www.woocommerce.com/mobile
GNU General Public License v2.0
276 stars 135 forks source link

App crashes on android 12 during a reader connection #5267

Closed kidinov closed 2 years ago

kidinov commented 2 years ago

https://developer.android.com/guide/topics/connectivity/bluetooth/permissions

021-11-18 18:46:20.773 15180-15180/com.woocommerce.android.prealpha E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.woocommerce.android.prealpha, PID: 15180
    java.lang.SecurityException: Permission Denial: starting Intent { act=android.bluetooth.adapter.action.REQUEST_ENABLE cmp=com.android.settings/.bluetooth.RequestPermissionActivity } from ProcessRecord{5bc84a3 15180:com.woocommerce.android.prealpha/u0a390} (pid=15180, uid=10390) requires android.permission.BLUETOOTH_CONNECT
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2425)
        at android.os.Parcel.createException(Parcel.java:2409)
        at android.os.Parcel.readException(Parcel.java:2392)
        at android.os.Parcel.readException(Parcel.java:2334)
        at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2284)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1743)
        at android.app.Activity.startActivityForResult(Activity.java:5404)
        at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:588)
        at androidx.core.app.ActivityCompat.startActivityForResult(ActivityCompat.java:239)
        at androidx.activity.ComponentActivity$2.onLaunch(ComponentActivity.java:211)
        at androidx.activity.result.ActivityResultRegistry$2.launch(ActivityResultRegistry.java:167)
        at androidx.fragment.app.Fragment$9.launch(Fragment.java:3507)
        at androidx.activity.result.ActivityResultLauncher.launch(ActivityResultLauncher.java:47)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectDialogFragment.observeEvents$lambda-8(CardReaderConnectDialogFragment.kt:198)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectDialogFragment.lambda$1uV5SDVGRNZQs4NtrOiA14ljO1g(Unknown Source:0)
        at com.woocommerce.android.ui.prefs.cardreader.connect.-$$Lambda$CardReaderConnectDialogFragment$1uV5SDVGRNZQs4NtrOiA14ljO1g.onChanged(Unknown Source:4)
        at com.woocommerce.android.viewmodel.SingleLiveEvent.observe$lambda-0(SingleLiveEvent.kt:52)
        at com.woocommerce.android.viewmodel.SingleLiveEvent.lambda$B2zauqpeSz_VYlwmzDz5fdMAYi0(Unknown Source:0)
        at com.woocommerce.android.viewmodel.-$$Lambda$SingleLiveEvent$B2zauqpeSz_VYlwmzDz5fdMAYi0.onChanged(Unknown Source:4)
        at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
        at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
        at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
        at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
        at com.woocommerce.android.viewmodel.SingleLiveEvent.setValue(SingleLiveEvent.kt:65)
        at com.woocommerce.android.viewmodel.ScopedViewModel.triggerEvent(ScopedViewModel.kt:29)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectViewModel.access$triggerEvent(CardReaderConnectViewModel.kt:68)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectViewModel$checkOnboardingState$1.invokeSuspend(CardReaderConnectViewModel.kt:216)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7838)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
     Caused by: android.os.RemoteException: Remote stack trace:
        at com.android.server.wm.ActivityTaskSupervisor.checkStartAnyActivityPermission(ActivityTaskSupervisor.java:1047)
        at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:975)
        at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:665)
        at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1201)
2021-11-18 18:46:20.773 15180-15180/com.woocommerce.android.prealpha E/AndroidRuntime:     at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1173)
peril-woocommerce[bot] commented 2 years ago
Fails
:no_entry_sign: Please add a feature label to this issue. e.g. 'feature: stats'

Generated by :no_entry_sign: dangerJS

hichamboushaba commented 2 years ago

Fixed by #5269

hichamboushaba commented 2 years ago

My bad, this is still happening, even though we are not targeting Android 12, the stacktrace is different though

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:558)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 
     Caused by: com.stripe.stripeterminal.external.models.TerminalException: You must request bluetooth permissions before initializing the Terminal
        at com.stripe.stripeterminal.PermissionsValidator.validatePermissions31(PermissionsValidator.kt:47)
        at com.stripe.stripeterminal.PermissionsValidator.validatePermissions$core_publish(PermissionsValidator.kt:17)
        at com.stripe.stripeterminal.Terminal$Companion.initTerminal(Terminal.kt:753)
        at com.woocommerce.android.cardreader.internal.wrappers.TerminalWrapper.initTerminal(TerminalWrapper.kt:35)
        at com.woocommerce.android.cardreader.internal.CardReaderManagerImpl.initStripeTerminal(CardReaderManagerImpl.kt:112)
        at com.woocommerce.android.cardreader.internal.CardReaderManagerImpl.initialize(CardReaderManagerImpl.kt:70)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectViewModel.onBluetoothStateVerified(CardReaderConnectViewModel.kt:201)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectViewModel.onCheckBluetoothResult(CardReaderConnectViewModel.kt:189)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectViewModel.access$onCheckBluetoothResult(CardReaderConnectViewModel.kt:68)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectViewModel$onLocationStateVerified$1.invoke(CardReaderConnectViewModel.kt:173)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectViewModel$onLocationStateVerified$1.invoke(CardReaderConnectViewModel.kt:173)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectDialogFragment.observeEvents$lambda-8(CardReaderConnectDialogFragment.kt:194)
        at com.woocommerce.android.ui.prefs.cardreader.connect.CardReaderConnectDialogFragment.lambda$1uV5SDVGRNZQs4NtrOiA14ljO1g(Unknown Source:0)
        at com.woocommerce.android.ui.prefs.cardreader.connect.-$$Lambda$CardReaderConnectDialogFragment$1uV5SDVGRNZQs4NtrOiA14ljO1g.onChanged(Unknown Source:4)
        at com.woocommerce.android.viewmodel.SingleLiveEvent.observe$lambda-0(SingleLiveEvent.kt:52)
        at com.woocommerce.android.viewmodel.SingleLiveEvent.lambda$B2zauqpeSz_VYlwmzDz5fdMAYi0(Unknown Source:0)
        at com.woocommerce.android.viewmodel.-$$Lambda$SingleLiveEvent$B2zauqpeSz_VYlwmzDz5fdMAYi0.onChanged(Unknown Source:4)
        at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
        at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
        at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:468)
        at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:425)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
        at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
        at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
        at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
        at androidx.fragment.app.FragmentViewLifecycleOwner.handleLifecycleEvent(FragmentViewLifecycleOwner.java:88)
        at androidx.fragment.app.Fragment.performStart(Fragment.java:3060)
        at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:587)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:279)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1840)
2021-11-20 14:37:09.696 21998-21998/com.woocommerce.android.prealpha E/AndroidRuntime:     at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1764)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1701)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:488)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
            ... 3 more

My guess is that the SDK is doing something weird in the function validatePermissions31 where they don't check the target SDK of the app.

hichamboushaba commented 2 years ago

I confirmed that the cause is an SDK's bug, the decompiled code of the com.stripe.stripeterminal.PermissionValidator has this:

public final void validatePermissions$core_publish() {
      this.validatePermissionsPre31();
      if (VERSION.SDK_INT >= 31) {
         this.validatePermissions31();
      }
   }
...
private final void validatePermissions31() {
      boolean bluetoothConnectGranted = this.isGranted("android.permission.BLUETOOTH_CONNECT");
      boolean bluetoothScanGranted = this.isGranted("android.permission.BLUETOOTH_SCAN");
      if (!bluetoothConnectGranted || !bluetoothScanGranted) {
         throw new TerminalException(TerminalErrorCode.BLUETOOTH_PERMISSION_DENIED, "You must request bluetooth permissions before initializing the Terminal", (ApiError)null, 4, (DefaultConstructorMarker)null);
      }
   }

So they require the new permissions for all apps running on Android 12 regardless of the target SDK version.