3

Is there any reason why an Android device could start a new process of an app with the same name, same user ID and different PID, and keep the old one still alive?

The manifest doesn't specify any other processes other than the default one.

The old process can be killed through a kill command in a terminal.

Is that an expected behaviour in some defined cases or is it an Android bug?

The manifest looks like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mycompany.myapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="19" />

    <!-- omitted <uses-permission> tags -->

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >

        <!-- Start up -->
        <activity
            android:name=".activity.SplashScreenActivity"
            android:configChanges="orientation|keyboardHidden" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- other non-launcher activities... -->

        <!-- Auto start on boot -->
        <receiver android:name=".receiver.StartEventsReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <!-- Update content and configuration -->
        <receiver
            android:name=".receiver.UpdateContentReceiver"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.mycompany.myapp.UPDATE_CONTENT" />
                <action android:name="com.mycompany.myapp.CONTENT_UPDATED" />
            </intent-filter>
        </receiver>
        <!-- other receivers and services... -->

    </application>

</manifest>

UPDATE: I've managed to get some logging. My app has a Receiver called UpdateContentReceiver (manifest above updated) that is called every minute with an UPDATE_CONTENT intent, posted from the main message queue. It does some network polling and finishes. It used to work...

08-30 09:46:57.419  2512  2512 V UpdateContentReceiver: Received UPDATE_CONTENT
08-30 09:46:58.349  2512  2512 V UpdateContentReceiver: No update

08-30 09:47:57.439  2512  2512 V UpdateContentReceiver: Received UPDATE_CONTENT
08-30 09:47:57.739  2512  2512 V UpdateContentReceiver: No update

08-30 09:48:57.439  2512  2512 V UpdateContentReceiver: Received UPDATE_CONTENT
08-30 09:49:02.389  2512  2512 V UpdateContentReceiver: No update

... but the next time...

08-30 09:49:57.459  1879  1904 E JavaBinder: !!! FAILED BINDER TRANSACTION !!!
08-30 09:49:57.469  1879  1904 W BroadcastQueue: Exception when sending broadcast to ComponentInfo{com.mycompany.myapp/com.mycompany.myapp.receiver.UpdateContentReceiver}
08-30 09:49:57.469  1879  1904 W BroadcastQueue: android.os.TransactionTooLargeException
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at android.os.BinderProxy.transact(Native Method)
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at android.app.ApplicationThreadProxy.scheduleReceiver(ApplicationThreadNative.java:771)
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at com.android.server.am.BroadcastQueue.processCurBroadcastLocked(BroadcastQueue.java:231)
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:778)
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at com.android.server.am.BroadcastQueue$1.handleMessage(BroadcastQueue.java:140)
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at android.os.Handler.dispatchMessage(Handler.java:99)
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at android.os.Looper.loop(Looper.java:137)
08-30 09:49:57.469  1879  1904 W BroadcastQueue:    at com.android.server.am.ActivityManagerService$AThread.run(ActivityManagerService.java:1487)
08-30 09:49:57.469  1879  1904 W ActivityManagerService: Scheduling restart of crashed service com.mycompany.myapp/.service.ServiceFoo in 5000ms
08-30 09:49:57.469  1879  1904 W ActivityManagerService: Scheduling restart of crashed service com.mycompany.myapp/.service.ServiceBar in 14999ms
08-30 09:49:57.469  1879  1904 W ActivityManagerServiceActivityStack_hong: Force removing ActivityRecord{42768bf8 u0 com.mycompany.myapp/.activity.MyActivity}: app died, no saved state
08-30 09:49:57.529  1879  1904 I ActivityManagerService: Start proc com.mycompany.myapp for broadcast com.mycompany.myapp/.receiver.UpdateContentReceiver: pid=27119 uid=10044 gids={50044, 3003, 1028, 1015, 1023}

The last line clearly says that a new process is created. After that, I see in the logs that MyApplication is started three times with different PIDs, until it settles with the last process living. Here's the ps|grep myapp output:

u0_a44    2512  1286  755540 85548 ffffffff 4003fee4 S com.mycompany.myapp                                                                      
u0_a44    28541 1286  772220 79204 ffffffff 4003fee4 S com.mycompany.myapp

I can't say why the TransactionTooLargeException happens (we only send UPDATE_CONTENT with no extras, so there's little memory footprint), but at least I know why a new process is created. Still it's unclear why the old process is not destroyed. The app has an internal web server: maybe Android sees that listening for a TCP port and refuses to kill it?

The funny thing is that the new process fails to run its own web server (because the listening port is already bound), but everything "works" because the old web server is still alive!

ris8_allo_zen0
  • 1,537
  • 1
  • 15
  • 35
  • Typically the name of a process is defined on a package name given to the application. If two application share the same package name such as com.mycompany then they will seem as though they are the same application in certain viewing environments. – Jay Snayder Aug 28 '14 at 14:34
  • You say there are two processes with the same name, but they have different PIDs, correct? – sschrass Aug 29 '14 at 07:24
  • @JaySnayder In the devices running this app, there's another app with the same package prefix and we can clearly distinguish them via the "ps" command. – ris8_allo_zen0 Aug 29 '14 at 07:55
  • @SatelliteSD correct. I edited the question. – ris8_allo_zen0 Aug 29 '14 at 08:00
  • @ris8_allo_zen0 could you append the relevant parts of the manifest to the question, namly `` and ``? – sschrass Aug 29 '14 at 08:46
  • @SatelliteSD here you are – ris8_allo_zen0 Aug 29 '14 at 11:07
  • another silly question: did you sign your apks differently? Is the latest from your IDE different than a previous one left over on your device which you are trying to start? – sschrass Aug 29 '14 at 12:38
  • In fact, we've never seen this issue on our test/dev machines but only "in the wild", in some of our remote machines. And when this happens, we notice it only few hours later, when the logcat has no useful info anymore. So there's no IDE involved: it's always the same APK that is run at device boot. – ris8_allo_zen0 Aug 29 '14 at 12:50
  • Finally got some useful logging during the weekend; the question is updated with more data. – ris8_allo_zen0 Sep 01 '14 at 09:16
  • @ris8_allo_zen0 Were you able to do anything to resolve this so that the original process also gets killed? I'm facing the same issue as you where I get Failed Binder transaction on attempting to send a broadcast with no extras. This kills my service & it restarts having 2 pids for the same name, which causes further exceptions in my app. Also, were you able to resolve the TransactionTooLargeException? – Kiran Parmar Feb 23 '16 at 08:56
  • @ris8_allo_zen0 hi! I guess we are suffering from the same issue. https://github.com/realm/realm-java/issues/2459 Do you have any way to constantly reproduce the issue (the old process keeps running without being killed by the OS)? – beeender Sep 22 '17 at 08:52
  • I moved away from that project a long ago; not sure if the issue is still there. Sorry! – ris8_allo_zen0 Sep 22 '17 at 09:50

1 Answers1

0

referring to this: Re-launch of Activity on Home button, but...only the first time or this: How to prevent multiple instances of an activity when it is launched with different intents

you could define your app as: android:launchMode="singleInstance" But I opt for:

if (!isTaskRoot()) {
    final Intent intent = getIntent();
    final String intentAction = intent.getAction(); 
    if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
        Log.w(LOG_TAG, "Main Activity is not the root.  Finishing Main Activity instead of launching.");
        finish();
        return;       
    }
}

Edit: (awaiting the manifest in the question)

android:multiprocess Whether an instance of the activity can be launched into the process of the component that started it — "true" if it can be, and"false" if not. The default value is "false".

Normally, a new instance of an activity is launched into the process of the application that defined it, so all instances of the activity run in the same process. However, if this flag is set to "true", instances of the activity can run in multiple processes, allowing the system to create instances wherever they are used (provided permissions allow it), something that is almost never necessary or desirable.

source: https://developer.android.com/guide/topics/manifest/activity-element.html

Community
  • 1
  • 1
sschrass
  • 7,014
  • 6
  • 43
  • 62
  • Note the question asks about a process, not an instance. Are you implying that you think it is has created a new process to host a new instance, instead of creating a new instance in the existing process? – Chris Stratton Aug 28 '14 at 15:37
  • without logs it is hard to tell for me, but I suspect both instances share the same process. The latest is spawned on top of the previous, so I check here if the Activity is the root for this process and shut it down if not. The process then, is brought to front and resumes the previous launched Activity. – sschrass Aug 29 '14 at 07:16
  • Oh! now I got you. I misread the question it seems. There are in fact two processes. I would doublecheck if this is the case. – sschrass Aug 29 '14 at 07:20