android google play integrity exponential backoff retry is blocking main application thread - google-play-integrity-api

// Create an instance of a manager.
IntegrityManager integrityManager =
    IntegrityManagerFactory.create(getApplicationContext());
// Request the integrity token by providing a nonce.
Task<IntegrityTokenResponse> integrityTokenResponse =
    integrityManager
        .requestIntegrityToken(
            IntegrityTokenRequest.builder().setNonce(nonce).build());
integrityTokenResponse.addOnSuccessListener(this::handleSuccess);
integrityTokenResponse.addOnFailureListener(this::handleFailure);
in handleFailure listener I have retry logic with Thread.sleep(retryMillis) which is running on main thread and blocking the UI requests.
Can someone help me how to do retry without blocking main thread or how to run play integrity in a different thread.?

After reading a bit more from this link, I realized that addOnFailureListener(this::handleFailure); constructor with a listener function always runs on main thread. I'm able to solve the problem by changing failurelistener as mentioned below by adding threadpool executor :
integrityTokenResponse.addOnFailureListener(executor, this::handleFailure);

Related

Detox tests hang with pending items on dispatch queue

I am writing e2e tests on Detox to test a Firebase app in React Native. It looks like the call to firebase.auth().signInWithPhoneNumber(number) dispatches some items on the dispatch queue but these items don't ever seem to be dequeued and therefore the tests cannot proceed. My hunch is that there is a network request being made by the sign in call that never resolves.
Here is the log:
detox[41991] INFO: [APP_STATUS] The app is busy with the following tasks:
• There are 2 work items pending on the dispatch queue: "Main Queue (<OS_dispatch_queue_main: com.apple.main-thread>)".
• Run loop "Main Run Loop" is awake.
I have read through this troubleshooting guide and it looks like the operation is on the Main thread (native) and the issue is a waiting too much issue.
Is there a way to inspect the items on the dispatch queue to further understand what they are? I have tried running the /usr/bin/xcrun simctl spawn <device> log stream --level debug --style compact --predicate 'process == "myapp"' but I don't understand the output. If it is useful I can upload the logs.
I'm hoping I can post some logs of some sort and someone can help me to find the reason for the items on the dispatch queue or point me in the right direction.
I have no experience with native development so device system logs and Objective C/Swift code mean nothing to me.
Thanks
Detox version: 19.4.2
React Native version: 0.67.4
Node version: v12.22.6
Device model: iPhone 11 Simulator
OS: iOS
Test-runner (select one): jest-circus
To answer the question: No,there is no easy way to inspect the dispatch queue. You must go through the internals of the app, add logging, and comment-out portions of the code until you figure out what is causing the issue.
EDIT: As of 2022-08-07, updating your #react-native-firebase/* packages to >=v15.3.0 should fix the issue.
About your specific synchronization problem...
This problem is caused by a bug in the #react-native-firebase/messaging implementation of application: didReceiveRemoteNotification: fetchCompletionHandler:[!].
Their implementation gets into a race with FIRAuth/didReceiveRemoteNotification which causes react-native-firebase/messaging to not callback the completion handler if FIRAuth's function ran first.
A PR is in progress for this to be fixed upstream, but in the meantime you can use the following patch if you have set-up patch-package:
diff --git a/node_modules/#react-native-firebase/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m b/node_modules/#react-native-firebase/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m
index ec26b70..743fe41 100644
--- a/node_modules/#react-native-firebase/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m
+++ b/node_modules/#react-native-firebase/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m
## -123,6 +123,18 ## - (void)application:(UIApplication *)application
completionHandler(UIBackgroundFetchResultNoData);
return;
}
+
+ // If the notification is a probe notification, always call the completion
+ // handler with UIBackgroundFetchResultNoData.
+ //
+ // This fixes a race condition between `FIRAuth/didReceiveRemoteNotification` and this
+ // module causing detox to hang when `FIRAuth/didReceiveRemoteNotification` is called first.
+ // see https://stackoverflow.com/questions/72044950/detox-tests-hang-with-pending-items-on-dispatch-queue/72989494
+ NSDictionary *data = userInfo[#"com.google.firebase.auth"];
+ if (data && data[#"warning"]) {
+ completionHandler(UIBackgroundFetchResultNoData);
+ return;
+ }
#endif
[[NSNotificationCenter defaultCenter]
[!]in #react-native-firebase/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m

Confusing crash on WebKit

Recently I encountered a WebKit crash problem, it is related to thread checking
0 WebKit WTFCrashWithInfo(int, char const*, char const*, int)()
1 WebKit WebKit::isMainThreadOrCheckDisabled()()
2 WebKit WebKit::WebProcessPool::createNewWebProcess(WebKit::WebsiteDataStore*, WebKit::WebProcessProxy::IsPrewarmed)()
3 WebKit WebKit::WebProcessPool::processForRegistrableDomain(WebKit::WebsiteDataStore&, WebKit::WebPageProxy*, WebCore::RegistrableDomain const&)()
4 WebKit WebKit::WebProcessPool::createWebPage(WebKit::PageClient&, WTF::Ref<API::PageConfiguration, WTF::DumbPtrTraits<API::PageConfiguration> >&&)()
5 WebKit -[WKContentView _commonInitializationWithProcessPool:configuration:]()
6 WebKit -[WKContentView initWithFrame:processPool:configuration:webView:]()
7 WebKit -[WKWebView _initializeWithConfiguration:]()
8 WebKit -[WKWebView initWithFrame:configuration:]()
I am sure the WKWebView was initialized on Main Thread, but isMainThreadOrCheckDisabled shows isn't. I even read the source code of WebKit, not able to find isMainThreadOrCheckDisabled be called in createNewWebProcess ,so do you have any idea?
After further reading the source code of WebKit, I find out
isMainThreadOrCheckDisabled check thread by RunLoop actually, which is
bool RunLoop::isMain()
{
ASSERT(s_mainRunLoop);
return s_mainRunLoop == &RunLoop::current();
}
and the &RunLoop::current() represents current thread, so s_mainRunLoop means Main Thread, because it is initialized on it
void RunLoop::initializeMain()
{
RELEASE_ASSERT(!s_mainRunLoop);
s_mainRunLoop = &RunLoop::current();
}
So, when run isMainThreadOrCheckDisabled on a background thread, it return false.
But the crash I encountered was happened on Main Thread, dose it means s_mainRunLoop not initialized on Main Thread? Or, is there any situation can WebKit be initialized on background thread?

UIApplication delegate must be used from main thread only - Swift

I am getting "runtime: UI API called from background thread: -[UIApplication delegate] must be used from main thread only
" runtime issue for Fabric initialisation line. Not sure how to solve it. Please help
Thanks
Fabric.with([Crashlytics.self,Zendesk.self])
It's because you are trying to access the UI from background thread. Just call the UI change in main thread.
DispatchQueue.main.async {
application.statusBarStyle = UIStatusBarStyle.lightContent
}
UI process are maintained under main thread.

app modifying the autolayout engine from a background thread [duplicate]

This question already has answers here:
Getting a "This application is modifying the autolayout engine from a background thread" error?
(21 answers)
Closed 6 years ago.
I am almost done migrating an iOS app of mine to Swift 3.0.
But I still have a few cases similar to the one below.
Most of them I have been able to solve by putting the problematic code on the main thread.
In some other cases, I can't figure out, which part of my code is executing on the wrong thread. And I get a message like this one:
This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
Stack:(
0 CoreFoundation 0x000000018765a1d8 <redacted> + 148
1 libobjc.A.dylib 0x000000018609455c objc_exception_throw + 56
2 CoreFoundation 0x000000018765a108 <redacted> + 0
3 Foundation 0x0000000188241ea4 <redacted> + 192
....................
16 libsystem_pthread.dylib 0x00000001866eece4 <redacted> + 200
17 libsystem_pthread.dylib 0x00000001866ee378 pthread_mutex_lock + 0
18 libsystem_pthread.dylib 0x00000001866edda4 start_wqthread + 4
)
Is there some special technic (option when using the debugger or ??) I can use to trace the path followed by the progran, to see where this is happening?
Obviously you are doing some UI update on back ground thread. Cant predict exactly where, without seeing your code.
These are some situations it might happen:-
you might be doing something on background thread and not using. Being in the same function this code is easier to spot.
DispatchQueue.main.async { // do UI update here }
calling a func doing web request call on background thread and its completion handler calling other func doing ui update.
to solve this try checking code where you have updated the UI after webrequest call.
// Do something on background thread
DispatchQueue.global(qos: .userInitiated).async {
// update UI on main thread
DispatchQueue.main.async {
// Updating whole table view
self.myTableview.reloadData()
}
}
I don't think there is any other inbuilt tool for debugging such crashes because it's the code which is modifying the AutoLayout UI elements/constraints from the code which is either running in Background thread or completion handlers. All completion handlers by default run in background thread. You need to use the GCD to update the UI elements from your completion handler blocks.

Make main thread wait until all other threads done in IPhone sdk

I am working on threads in objective C for the first time in my coding experience. In my app i needs to download some assets in two threads. After completion of downloading i have to start my main thread which will make use of the downloaded assets in threads. So i wrote some code like this
NSThread *threadPlayer1 = [[NSThread alloc]initWithTarget:self selector:#selector(getPlayer1Assets) object:nil];
           
[threadPlayer1 start];
           
NSThread *threadPlayer2 = [[NSThread alloc]initWithTarget:self selector:#selector(getPlayer2Assets) object:nil];
           
[threadPlayer2 start];
[self performSelectorOnMainThread:#selector(introducePlayer1) withObject:nil waitUntilDone:YES];
I wrote waituntilDone to Yes but it waits until the first thread completes only.
so if i wants to wait untill all the two threads completed what should i do? can any one suggest with sample code snippets.
What I would suggest, would be to use this. It's from Pulse Engeenering Blog. Spend a bit of time in it, until you grasp the idea.
As for your code. I guess you are doing this:
[self performSelectorOnMainThread:#selector(introducePlayer1) withObject:nil waitUntilDone:YES];
On the main thread. Read what is said about it on the documentation, specially the last sentence:
wait A Boolean that specifies whether the current thread blocks until
after the specified selector is performed on the receiver on the main
thread. Specify YES to block this thread; otherwise, specify NO to
have this method return immediately.
If the current thread is also the main thread, and you specify YES for
this parameter, the message is delivered and processed immediately.

Resources