(android-12)app在后台运行,点击桌面图标重新启动问题

工作中遇到这么个问题,com.kos.launcher是自写app,运行该app,并切到后台,然后点击桌面com.kos.launcher图标。出现行为不是com.kos.launcher被切到前台,而是重新启动了com.kos.launcher这个app。

 

一、app层:修改onCreate

处理app在后台运行,点击桌面图标重新启动问题”提供种解决办法:判断启动页是否是根任务,如果不是,则不初始化启动页。在启动页的onCreate添加下面代码。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (!isTaskRoot()&& getIntent().getAction() != null) {
            finish()
            return
        }
        super.onCreate(savedInstanceState)
    }

经过这么修改后,等android启动完成,再手动运行com.kos.launcher,似乎是得到了期望结果。也说就是,再点击图标,是把com.kos.launcher切到前台。但是,如果com.kos.launcher是随机启动,那第一次单击图标时,还是会杀死原来那个com.kos.launcher。

要求com.kos.launcher必须随机启动,只好试着修改android源码。

 

二、android源码:修改Task.isSameIntentFilter

系统维护着一个当前正运行哪些app的列表,当点击com.kos.launcher图标,如果从列表能找到对应app,会把com.kos.launcher切到前台。否则要运行一个新的com.kos.launcher,由于列表中有一个旧的com.kos.launcher,于是看到行为是旧的com.kos.launcher被杀死,新的被运行。

不论旧的,还是新的,bundleid都是com.kos.launcher,但android在判断列表中是否存在正单击桌面图标的app时,应该不止bundleid必须相同,还有其它条件。查下来问题出在Task.isSameIntentFilter。

<aosp>/frameworks/base/services/core/java/com/android/server/wm/Task.java
------
class Task extends TaskFragment {
    boolean isSameIntentFilter(ActivityRecord r) {
        final Intent intent = new Intent(r.intent);
        // Make sure the component are the same if the input activity has the same real activity
        // as the one in the task because either one of them could be the alias activity.
        if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
            intent.setComponent(this.intent.getComponent());
        }
        if (intent.getComponent() != null && intent.getComponent().getPackageName() != null) {
            // 这个if块是我加的,com.kos.launcher时,强制认为一样。
            String rPackageName = r.mActivityComponent.getPackageName();
            if (intent.getComponent().getPackageName().equals(rPackageName) && rPackageName.equals("com.kos.launcher")) {
                Slog.d(TAG, "{leagor}isSameIntentFilter(1), it is " + rPackageName + " always return true");
                Slog.d(TAG, "{leagor}isSameIntentFilter(2), intent: " + intent + " this.intent: " + this.intent);
                return true;
            }
        } 
        
        return intent.filterEquals(this.intent);
    }
}

解决办法是修改isSameIntentFilter,增加那第二个if。让bundleid是com.kos.launcher,总是返回一致。以下是出问题的两个intent。

intent: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10600000 cmp=com.kos.launcher/.app bnds=[960,194][1275,335] } 
this.intent: Intent { flg=0x10000000 cmp=com.kos.launcher/.app }

用了这种方法后,没必要用上面写的修改onCreate了。

 

三、何时调用Task.isSameIntentFilter

为查看更多android运行时日志,建议打开几个输出。

<aosp>/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
------
static final boolean DEBUG_ALL = true;
 
<aosp>/frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
------
private static final boolean DEBUG_RESOLVER = true;

如果想再看更低层的performLaunchActivity、handleLaunchActivity。修改这个,编译时间会较长。
<aosp>/frameworks/base/core/java/android/app/ActivityThread.java
------
static final boolean localLOGV = true;

网上有文章描述Android Activity启动过程,像“Android Activity——启动过程探索(二)”。

class ActivityStarter;
class Task extends TaskFragment;
class TaskFragment extends WindowContainer<WindowContainer>;

ActivityStarter.executeRequest
  ActivityStarter.startActivityUnchecked
    ActivityStarter.startActivityInner
      ActivityStarter.recycleTask
        ActivityStarter.setTargetRootTaskIfNeeded。
        ActivityStarter.complyActivityFlags

ActivityStarter.complyActivityFlags会调用Task.isSameIntentFilter。以下是通过看两处logcat定位问题。

第一处:“Prepare open transition”、“Resuming”

出错时(点击图标重新运行了app)

V/ActivityTaskManager: moveTaskToFront: Task{282c450 #13 type=standard A=10078:com.kos.launcher U=0 visible=false visibleRequested=false mode=fullscreen translucent=true sz=1}
V/ActivityTaskManager: Prepare to front transition: task=Task{282c450 #13 type=standard A=10078:com.kos.launcher U=0 visible=true visibleRequested=false mode=fullscreen translucent=true sz=1}
I/ActivityTaskManager: Update options for ActivityRecord{7fbb24d u0 com.kos.launcher/.app t13}
V/ActivityTaskManager: Prepare open transition: starting ActivityRecord{b2a2e8c u0 com.kos.launcher/.app t13}

正确时(点击图标把app切到前台)

V/ActivityTaskManager: moveTaskToFront: Task{ae03f6f #14 type=standard A=10078:com.kos.launcher U=0 visible=false visibleRequested=false mode=fullscreen translucent=true sz=1}
V/ActivityTaskManager: Prepare to front transition: task=Task{ae03f6f #14 type=standard A=10078:com.kos.launcher U=0 visible=true visibleRequested=false mode=fullscreen translucent=true sz=1}
I/ActivityTaskManager: Update options for ActivityRecord{a62924e u0 com.kos.launcher/.app t14}
V/ActivityTaskManager: Resuming ActivityRecord{a62924e u0 com.kos.launcher/.app t14}

第四条由“Prepare open transition ...”变成了“Resuming ActivityRecord...”。

第二处:TransactionExecutor.execute的ClientTransaction参数

过程中会调用TransactionExecutor.execute。

<aosp>/frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
------
public void execute(ClientTransaction transaction)

DEBUG_RESOLVER==true时,会用transactionToString(transaction, mTransactionHandler)向logcat输出参数ClientTransaction信息。

出错时(点击图标重新运行了app)

1888-1888/com.kos.launcher D/TransactionExecutor: tId:-1211256274 Start resolving transaction
1888-1888/com.kos.launcher D/TransactionExecutor: tId:-1211256274 ClientTransaction{
    tId:-1211256274   callbacks=[
    tId:-1211256274     LaunchActivityItem{intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10600000 cmp=com.kos.launcher/.app bnds=[960,194][1275,335] },ident=187313804,info=ActivityInfo{e0126d com.kos.launcher.app},curConfig={1.0 ?mcc?mnc [en_US] ldltr sw617dp w1097dp h545dp 280dpi lrg long land -touch -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1080) mAppBounds=Rect(0, 0 - 1920, 996) mMaxBounds=Rect(0, 0 - 1920, 1080) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.2 s.8 fontWeightAdjustment=0},overrideConfig={1.0 ?mcc?mnc [en_US] ldltr sw617dp w1097dp h545dp 280dpi lrg long land -touch -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1080) mAppBounds=Rect(0, 0 - 1920, 996) mMaxBounds=Rect(0, 0 - 1920, 1080) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} as.2 s.1 fontWeightAdjustment=0},referrer=null,procState=10,state=null,persistentState=null,pendingResults=null,pendingNewIntents=null,options=null,profilerInfo=null,assistToken=android.os.BinderProxy@6d6a897,rotationAdj=null,shareableActivityToken=android.os.BinderProxy@c8dfa84}
    tId:-1211256274   ]
    tId:-1211256274   stateRequest=ResumeActivityItem{procState=-1,updateProcState=false,isForward=true}
    tId:-1211256274 }
    tId:-1211256274 Target activity: Not found for token: android.os.BinderProxy@309c716

android没有找到该app,于是LaunchActivityItem,重新Launche一个。

正确时(点击图标把app切到前台)

2134-2134/com.kos.launcher D/TransactionExecutor: tId:899264136 Start resolving transaction
2134-2134/com.kos.launcher D/TransactionExecutor: tId:899264136 ClientTransaction{
    tId:899264136   callbacks=[
    tId:899264136     TopResumedActivityChangeItem{onTop=true}
    tId:899264136   ]
    tId:899264136   stateRequest=null
    tId:899264136 }
    tId:899264136 Target activity: com.kos.launcher.app

android找到了该app,于是TopResumedActivityChangeItem,把该app切到前台。

全部评论: 0

    写评论: