Android - Myth of Foreground service

    Android developers have a misconception that having a service as foreground with user's knowledge ensures that their process can't be killed by Android's low memory killer. And to make things worse, the developer documentation too is misleading,

A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory.

Is that really the case? Assuming that premise to be valid, what would happen when multiple applications launch foreground services? Time to bust the myth !!!  For simplicity, lets have an application launch a number of services each in its own process space have largeHeap enabled. In this case, a single apk has 20 services each running in its own process space. The services are started as not sticky to ensure that they aren't restarted by Android Framework, besides as per the documentation they are not candidates to be killed, so it shouldn't matter. On top of this, each service allocates a byte array of 110 MB.

public class MyService extends Service {

    byte[] mArray;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        this.startForeground(1234, new Notification());
        int size = 1024 * 1024 * 110; // 100 MB
        mArray = new byte[size];
        return START_NOT_STICKY;
    }

}

        <service
            android:name=".MyService"
            android:process="com.android.myService"
            android:enabled="true"
            android:exported="false" >
        </service>

The main activity starts these services one after the other with a delay of 5 seconds,

    private void startForegroundService(final Class<?> serviceClass) {
        mHandler.postDelayed(new Runnable() {

            @Override
            public void run() {

                Intent intent = new Intent();
                intent.setClass(MyActivity.this, serviceClass);
                startService(intent);

            }
        }, mDelay);

        mDelay += 5000;
    }

So this should result in 20 different process each hosting an instance of the service and 20 notification icons too. However, as and when services was being launched with a delay of 5 seconds, notifications would appear and disappear and eventually ends up with 5 notifications. This was tested in a LGE's G2 running Kitkat, 4.4.2.


  The notification of the other services disappear as the low memory killer kills them due to memory shortage.

Start proc com.android.myService5 for service com.example.sam_cit.foregroundservice1/.MyService5: pid=3696 uid=10243 gids={50243}
Process com.android.myService3 (pid 3481) has died
Start proc com.android.myService6 for service com.example.sam_cit.foregroundservice1/.MyService6: pid=3740 uid=10243 gids={50243}
ActivityManager: Process com.android.myService4 (pid 3624) has died.

   This is really more of a worst case scenario where in each foreground service consumes a lot of memory, however this is a possibility and is a good reason as to why developer should still consider handling termination of foreground service. Should the music playback continue after being restarted by Android framework? (assuming the service was started as STICKY). Finally, the claim that foreground service aren't candidates is possible in a system with infinite memory. But then, why gamble when having infinite money?

No comments: