Dealing with Samsung SPCM killer

2019-01-22 16:53发布

Lately we acquired a new Galaxy S6 with Android 5.1.1 and we are having some troubles with the new Samsung SPCM memory manager that comes with it. It is aggressively closing our app's background service, which even though is set to START_STICKY, it is not being restarted.

Additionally, the service takes no more than 5MB of RAM, but still somehow we end up with the lowest score of the SPCM algorithm and gets chosen to be killed.

This is our service:

Public class IncomingService extends Service {

    @Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    return START_STICKY;

}

@Override
public void onCreate() {
    if (mPhoneListener == null) {
        mPhoneListener = new CallStateListener();
        TelephonyManager tm = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
        tm.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}

    /**
 * Listener for call states
 * Listens for different call states
 */
private class CallStateListener extends PhoneStateListener {

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
       // Doing something with incomingNumber
    }
}

And in the manifest:

    <service
        android:name="com.services.IncomingService"
        android:enabled="true"
        android:priority="999" >
    </service>    

A log of SPCM killing our services:

Force stopping com.special.app appid=10499 user=0: SPCM kill lowestscore package!
03-18 22:48:11.280 3562-3562/? I/ActivityManager: Killing 2279:com.special.app/u0a499 (adj 8): stop com.special.app cause SPCM kill lowestscore package!
03-18 22:48:11.280 3562-3562/? W/ActivityManager: Scheduling restart of crashed service com.special.app/com.services.IncomingService in 1000ms
03-18 22:48:11.280 3562-3562/? I/ActivityManager:   Force stopping service ServiceRecord{27d2c408 u0 com.special.app/com.services.IncomingService}

Even though the ActivityManager log states it is rescheduling a restart for our service, it never actually gets restarted.

We have seen the same SPCM logs regarding other apps (Facebook, TrueCaller, etc.) but their services somehow manage to restart.

So to sum up, our questions are:

  1. How to prevent SPCM from targeting our app as lowestscore package?
  2. If we have been targeted, how to make sure our service will be successfully restarted after getting killed?
  3. Any other ideas that can help us?

2条回答
小情绪 Triste *
2楼-- · 2019-01-22 17:09

Make sure that ActivityManager is not targeting your service too.

AFAIK there's no other way to ensure survival than having a persistent notification, that's also what Samsung's developer docs state. As for Facebook and TrueCaller I have no answers. Possibly they leverage other related processes to get services back up.

As for devices affected, the earliest I saw was a Galaxy Tab S SM-T805 with 5.0.2. A lot of 5.1.1 Samsung devices have SPCM too. We initially reproduced the issue on a S6 also and I can confirm that it's still present on 6.0.1.

As for documentation, this Samsung forums topic goes as far as it possible.

For testing and reproduction steps I advise to:

  1. Ensure that the device actually has SPCM adb shell getprop | grep spcm.
  2. Unplug it from any power sources.
  3. Install Tinycore to observe RAM usage (enable persistent notification for it).
  4. Load a lot of RAM hungry apps to bump your services score down. Alternatively try the Developer Toolbelt, it should be faster than filling it by hand but I haven't tested it.
  5. Turn off the screen and give the device 15 minutes.
  6. adb shell logcat -v threadtime | grep spcm to confirm that processes got killed.
  7. Rinse and repeat until successful.
查看更多
Fickle 薄情
3楼-- · 2019-01-22 17:11

I will try to help you answering your 3rd question:

I'm facing the same issue and the best workaround I found is to use AlarmManager to start my service. So I set AlarmManager to run each 30 minutes and start my service. If it's still running, onStartCommand will be called again, otherwise service will be recreated. I did some adjustments in my code to deal with new calls to onStartCommand each 30 minutes and it's working the way I expected. The downside is the battery drain, since my service is always running and Android is never entering in sleep mode (still working on it). Another approach is to set your service to run in foreground, but in my case it's not I want to do.

You can try to disable SPCM, open your build.prop and change the following line (requires root):

sys.config.spcm_enable=true

to:

sys.config.spcm_enable=false

Take a look here and here.

Hope it helps.

查看更多
登录 后发表回答