A bug in PackageInstaller app. Relate to activity task affinity.

来源:互联网 发布:java面试视频 编辑:程序博客网 时间:2024/06/08 10:43

In Android system, AMS will create a new task when it start a new activity. The task's name is got from taskAffinity attribute defined inAndroidManifest.xml (The default value of taskAffinity is package name).

So all the activities in one package will be put in a same task if develop does not settaskAffinity attribute for them.

For example, in packages/apps/PackageInstaller/AndroidManifest.xml it defines two activities.

1<?xml version="1.0" encoding="utf-8"?>2<manifest xmlns:android="http://schemas.android.com/apk/res/android"3          package="com.android.packageinstaller" coreApp="true">45    <original-package android:name="com.android.packageinstaller" />2425    <application android:label="@string/app_name"26            android:allowBackup="false"27            android:theme="@style/Theme.DialogWhenLarge"28            android:supportsRtl="true"29            android:defaultToDeviceProtectedStorage="true"30            android:directBootAware="true">3132        <activity android:name=".PackageInstallerActivity"33                android:configChanges="orientation|keyboardHidden|screenSize"34                android:excludeFromRecents="true">35            <intent-filter>36                <action android:name="android.intent.action.VIEW" />37                <action android:name="android.intent.action.INSTALL_PACKAGE" />38                <category android:name="android.intent.category.DEFAULT" />39                <data android:scheme="file" />40                <data android:scheme="content" />41                <data android:mimeType="application/vnd.android.package-archive" />42            </intent-filter>43            <intent-filter>44                <action android:name="android.intent.action.INSTALL_PACKAGE" />45                <category android:name="android.intent.category.DEFAULT" />46                <data android:scheme="file" />47                <data android:scheme="package" />48                <data android:scheme="content" />49            </intent-filter>50            <intent-filter>51                <action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" />52                <category android:name="android.intent.category.DEFAULT" />53            </intent-filter>54        </activity>5556        <activity android:name=".InstallAppProgress"57                android:configChanges="orientation|keyboardHidden|screenSize"58                android:exported="false" />142    </application>144</manifest>

从这个AndroidManifest.xml文件中,定义了2个activity,它们都没有指定自己的taskAffinity。所以默认它们的taskAffinity都是package name。

当用户要安装一个apk时,系统就会启动PackageInstallerActivity。这时的stack/task结果如下:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #12
    * TaskRecord{10e8876a #12 A=com.android.packageinstaller U=0 sz=1}
      userId=0 effectiveUid=u0a22036 mCallingUid=u0a22056 mCallingPackage=com.amazon.cloud9
      affinity=com.android.packageinstaller
      intent={act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.PackageInstallerActivity}
      * Hist #0: ActivityRecord{1b5044b0 u0 com.android.packageinstaller/.PackageInstallerActivity t12}
          packageName=com.android.packageinstaller processName=com.android.packageinstaller
          launchedFromUid=32056 launchedFromPackage=com.amazon.cloud9 userId=0
          app=ProcessRecord{3240245b 14805:com.android.packageinstaller/u0a22036}
          Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.PackageInstallerActivity }


From the dumpsys, we know AMS create a new task(#12). It's affinity is "com.android.packageinstaller", and it's intent is "act=android.intent.action.VIEW.......".The intent is used as an identifier of the task. When processing intent, AMS will search for a task which match the intent first.


User can tap install button to launch app installation activity. Stack/task dumpsys as follows.

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #12
    * TaskRecord{10e8876a #12 A=com.android.packageinstaller U=0 sz=2}
      userId=0 effectiveUid=u0a22036 mCallingUid=u0a22056 mCallingPackage=com.amazon.cloud9
      affinity=com.android.packageinstaller
      intent={act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.PackageInstallerActivity}
      realActivity=com.android.packageinstaller/.PackageInstallerActivity
      * Hist #1: ActivityRecord{3ec0f82e u0 com.android.packageinstaller/.InstallAppProgress t12}
          packageName=com.android.packageinstaller processName=com.android.packageinstaller
          launchedFromUid=32036 launchedFromPackage=com.android.packageinstaller userId=0
          app=ProcessRecord{3240245b 14805:com.android.packageinstaller/u0a22036}
          Intent { dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk cmp=com.android.packageinstaller/.InstallAppProgress (has extras) }
      * Hist #0: ActivityRecord{1b5044b0 u0 com.android.packageinstaller/.PackageInstallerActivity t12 f}
          packageName=com.android.packageinstaller processName=com.android.packageinstaller
          launchedFromUid=32056 launchedFromPackage=com.amazon.cloud9 userId=0
          app=ProcessRecord{3240245b 14805:com.android.packageinstaller/u0a22036}
          Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.PackageInstallerActivity }


From this dumpsys, we can see that a new activity record was added in current task. And the task's affinity and intent keep unchange.


After installation finish, the stack and task as follows.

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #12
    * TaskRecord{10e8876a #12 A=com.android.packageinstaller U=0 sz=1}
      userId=0 effectiveUid=u0a22036 mCallingUid=u0a22036 mCallingPackage=com.android.packageinstaller
      affinity=com.android.packageinstaller
      intent={act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.PackageInstallerActivity}
      realActivity=com.android.packageinstaller/.PackageInstallerActivity
      * Hist #0: ActivityRecord{3ec0f82e u0 com.android.packageinstaller/.InstallAppProgress t12}
          packageName=com.android.packageinstaller processName=com.android.packageinstaller
          launchedFromUid=32036 launchedFromPackage=com.android.packageinstaller userId=0
          app=ProcessRecord{3240245b 14805:com.android.packageinstaller/u0a22036}
          Intent { dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk cmp=com.android.packageinstaller/.InstallAppProgress (has extras) }

There is only one activity in the task now. And the task's attribute keep unchange.

In this screen, user can tap "Done" button to close current screen, or "Open" button to start the app just installed.InstallAppProgress activity will always finish no matter user tap"Done" button or"Open" button.


第一种情况:There is a special case: userdon't tap"Done" button or"Open" button, he tap home key or recents key instead.

In this case, InstallAppProgress activity will not finish, and it can't be shown in Recents activity also.


第二种情况:除了上面说的情况外,还有一个种情况可以使com.android.packageinstaller task不退出。

即用户启动了PackageInstallerActivity,然后不点击“退出”或“安装”,而是点击home key,或者recent key。这时task同样也会退到后台。


出现了上面的两种情况后,会对用户再次安装app造成影响。因为这时的Stack/task情况如下:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #12
    * TaskRecord{10e8876a #12 A=com.android.packageinstaller U=0 sz=2}
      userId=0 effectiveUid=u0a22036 mCallingUid=u0a22056 mCallingPackage=com.amazon.cloud9
      affinity=com.android.packageinstaller
      intent={act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.PackageInstallerActivity}
     
realActivity=com.android.packageinstaller/.PackageInstallerActivity*

     * Hist #1: ActivityRecord{1b5044b0 u0 com.android.packageinstaller/.PackageInstallerActivity t12 f}*(如果是第一种情况,则不会有这个activity)
        Hist #0: ActivityRecord{3ec0f82e u0 com.android.packageinstaller/.InstallAppProgress t12}


在这种情况下,如果用户要启动PackageInstallerActivity安装app,则有如下几种情况:

1. 如果要安装的app和该task的intent匹配(如:act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk,则AMS直接把task resume到前台。(例如:如果用户通过PackageInstallerActivity安装了A.apk,在安装完成界面上几点了home key,然后卸载了A.apk。之后再想通过PackageInstallerActivity安装A.apk时,会弹出安装完成界面,而不是待安装界面)

2.如果该task的intent不能匹配要安装的app(即要安装的app不是intent中dat域指定的app),则AMS会启动一个新的PackageInstallerActivity并把这个activity放在该task的第一个位置。


例如:上面的例子中,task的intent是用于安装shoujibaidu_37750016.apk,如下:

intent={act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.PackageInstallerActivity}

如果我们要安装另一个apk,如channel_66207888_1000047_1501228022346.apk。则AMS会启动另一个PackageInstallerActivity,之后stack如下:


ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #12
    * TaskRecord{10e8876a #12 A=com.android.packageinstaller U=0 sz=2}
      intent={act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.Pack
ageInstallerActivity}

      * Hist #1: ActivityRecord{1f256505 u0 com.android.packageinstaller/.PackageInstallerActivity t12}
          Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/channel_66207888_1000047_1501228022346.apk typ=application/vnd.android.package-archive flg=0x10c00000 cmp=com.android
.packageinstaller/.PackageInstallerActivity }

      * Hist #0: ActivityRecord{3ec0f82e u0 com.android.packageinstaller/.InstallAppProgress t12}
          Intent { dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk cmp=com.android.packageinstaller/.InstallAppProgress (has extras) }


这时,如果我们按home key,然后再试图安装channel_66207888_1000047_1501228022346.apk,AMS发现task的intent仍然不匹配对应的app安装,会再启动一个PackageInstallerActivity,如下:


ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #12
    * TaskRecord{10e8876a #12 A=com.android.packageinstaller U=0 sz=3}
      intent={act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk typ=application/vnd.android.package-archive flg=0x10800000 cmp=com.android.packageinstaller/.Pack
ageInstallerActivity}

      * Hist #2: ActivityRecord{1c9655c7 u0 com.android.packageinstaller/.PackageInstallerActivity t12} (和Hist #1一样
          Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/channel_66207888_1000047_1501228022346.apk typ=application/vnd.android.package-archive flg=0x10c00000 cmp=com.android
.packageinstaller/.PackageInstallerActivity }

      * Hist #1: ActivityRecord{1f256505 u0 com.android.packageinstaller/.PackageInstallerActivity t12}
          Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/channel_66207888_1000047_1501228022346.apk typ=application/vnd.android.package-archive flg=0x10c00000 cmp=com.android
.packageinstaller/.PackageInstallerActivity }

      * Hist #0: ActivityRecord{3ec0f82e u0 com.android.packageinstaller/.InstallAppProgress t12}
          Intent { dat=file:///storage/emulated/0/Download/shoujibaidu_37750016.apk cmp=com.android.packageinstaller/.InstallAppProgress (has extras) }


解决方案:

1.要解决第一个问题,可以把安装完成界面InstallAppProgress放到另一个task(例如叫TaskInstall)中,然后在启动它的时候设置clear top 标志,保证task只有一个InstallAppProgress,且每次都是重新创建的。

因为InstallAppProgress只通过PackageInstallerActivity启动,且不再recent 列表中,所以用户必然先看见PackageInstallerActivity,再看见InstallAppProgress

如果出现问题1描述的情况,当用户想再次安装A.apk时,会先启动PackageInstallerActivity。用户决定安装后,会启动InstallAppProgress,这时如果TaskInstall已经有一个InstallAppProgress,会先销毁当前这个,在启动一个新的。

2. 要解决第二个问题,需要把PackageInstallerActivity设置为singleTask,这样的话,就不会再同一个task中出现多个PackageInstallerActivity。每次启动的PackageInstallerActivity的intent,可以通过onNewIntent接口获得。这样可以保证每次的PackageInstallerActivity界面都是用于安装用户最新请求的apk。

0 0
原创粉丝点击