androidbroadcastreceiverandroid-phone-call

What could make a BroadcastReceiver to get its intents so late?


Background

We have a large app that has various features, uses multiple libraries, and handles phone calls using a BroadcastReceiver:

    <receiver android:name="....PhoneBroadcastReceiver">
        <intent-filter >
            <action android:name="android.intent.action.PHONE_STATE"/>
        </intent-filter>
        <intent-filter >
            <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
        </intent-filter>
    </receiver>

The problem

Recently I've noticed that if we close the app using the recent-tasks, the BroadcastReceiver receives intents quite a lot of time (3-5 seconds) after the phone starts ringing.

This is a problem, because the app needs to handle the phone calls right away.

What I've tried and found

  1. In a POC, it seems to work just fine. Even on one of my repositories (here), which is meant for phone call recording, if I add logs in the BroadcastReceiver instead of the real logic, I can see it gets handled right away. I even added all of the permissions of the large app into this sample app I've made (and granted them), and it still worked perfectly fine. Adding the libraries the large app uses could take a lot of time to add and test, sadly

  2. I was thinking that maybe the class that extends from Application (or MultiDexApplication, to be precise) was taking too much time, so I added a log there (beginning of onCreate). It does indeed take a bit of time (a second or so), but the log is shown after a while, and the difference between it and the log of the BroadcastReceiver is very small. So the issue should be caused by something much deeper than the Application or the BroadcastReceiver.

  3. I thought that maybe it's because we use multi-dexing. I tried to disable it but it didn't help. I don't think it can even affect it, as I've tried it on Android P on Pixel 2.

  4. I tried to set the priority of the BroadcastReceiver. Tried to set it to 999 (which is the max allowed), and even to 2147483647 , but none of those helped.

  5. I thought that maybe the OS is allocating a lot of memory for the app, which could take some time, but I know that other apps that listen to the same Intents (such as TrueCaller) work fine even after I close the app from the recent tasks. I also tested how much memory the app uses, and how much TrueCaller uses. The app uses average 33MB of total RAM on my Pixel 2, while TrueCaller uses 2MB . I got these values from the developer options screen, of "memory usage". Weird thing is that it tells the max RAM usage is huge (around 1GB) even when starting the app from scratch, but I never saw it in the profiler, not even close (around 200MB). I think this screen it not a reliable way to check the memory usage.

  6. I thought that maybe excluding the app from battery optimizations could help, but it didn't. Even TrueCaller, which request this from users, don't really need it in this scenario. It works fine there without setting it.

  7. The only thing that I think could be the reason for this, it the libraries the app uses. And there are a lot, but I wonder what could affect the app even before the class that extends Application is being called... Sadly there are so many that it would take a lot of time to add them all into POC project. I think I will do it, but I wonder if it can actually be the reason.

The questions

  1. What could possibly affect the BroadcastReceiver to get its intent so late? Is it one of the things I've mentioned perhaps?

  2. Why does the "memory usage" screen seem so unreliable and contradicting what I see on the profiler of the IDE ? Could it be the reason for the late Intent (huge memory allocation of the OS) ?


EDIT: I've noticed that some libraries initializations took too much time in the onCreate call of the class that extends Application, so I've put some of them in background threads, and some I've even removed.

Seems it's better, but still, the problem is that the app gets triggered too late after the phone rings, and so the issue still exists.


Solution

  • OK, seems that I was wrong, and that this Intent can be received a bit late, depending on the OS and maybe on how light the app is.

    The reason that I think this way now, is that I've noticed that even TrueCaller doesn't always appear immediately. Sometimes it can take them a very long time too.

    So the only way I think it's safe to listen to those intents, is programmatically and not via the manifest.

    Meaning something like that in a foreground service:

            telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            telephonyManager!!.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
    

    What I can say, is that if the app has notification access permission granted, it has a very large chance of always being alive, so it won't need a foreground service.