在阅读Adnroid O的源码时,发现O中2个小变化。
DocumentsUI
首先,是DocumentsUi模块的源码放置路径发生了变化
user@swd3:/local/sdb/code/u5ago/frameworks/base/packages/DocumentsUI$ ll
total 8
drwxrwxr-x 2 user user 18 Oct 10 21:10 ./
drwxrwxr-x 34 user user 4096 Oct 10 21:10 ../
-rw-rw-r-- 1 user user 38 Oct 10 21:10 MOVED
user@swd3:/local/sdb/code/u5ago/frameworks/base/packages/DocumentsUI$
user@swd3:/local/sdb/code/u5ago/frameworks/base/packages/DocumentsUI$ cat MOVED
../../../../packages/apps/DocumentsUI
修改后,将其放置在了packages/apps/DocumentsUI下,不知是基于何种考量,竟然将一成不变的路径换了。
也许是基于Apps的方便管理,对比了Android 7.1.1和Android 8中二者的Android.mk和Manifest,并未发现其明显意图。
Unknown source
第二个变化是,当用户想安装从地3方平台中下载APK时,对未知来源的APK安装处理方式发生了变化。
先上图。。。
1)首先是Android O的表现
2) 其次是Android N的表现。
单从行为上来看,
N之前的做法,只要用户在Settings中开启允许了未知来源APK的安装,倘若未及时关闭,第二个应用是可以直接进行安装,无再次二次提示。
O中的表现,则优化不少,每个非信任来源的APK安装,都会给予用户相应的提示,未进过允许,是无法进行安装的。即可以理解为动态赋予每个未知来源APK临时安装授权。
有点很显然,为用户增加了一道安全性屏障,可以更加有效地放置恶意软件的侵扰。
补充:
以上是直接通过DocumentsUI模块,直接点击打开taginfo.apk进行安装。
未知来源APK安装
从log来看,无论是Android O还是N,DocumentsUI都不直接进行应用安装的动作,只是通过当前所点击的文件类型发送隐式Intent来启动PackageInstaller模块来负责应用的安装,包括以上提示信息。
那么,启动未知来源APK安装的隐式Intent是怎么发出来的呢?
据跟踪得如下信息。
来源于ActionHandler类中的boolean viewDocument(DocumentInfo doc),安装文件应该是manageDocument(DocumentInfo doc)方法,根据apk文件的mimeType和drivedUri来创建Intent,AMS通过此找到了PackageInstaller模块。boolean viewDocument(DocumentInfo doc)用于查看文件,例如打开图片。
/packages/apps/DocumentsUI/src/com/android/documentsui/files/ActionHandler.java
private Intent buildViewIntent(DocumentInfo doc) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(doc.derivedUri, doc.mimeType);//核心点
// Downloads has traditionally added the WRITE permission
// in the TrampolineActivity. Since this behavior is long
// established, we set the same permission for non-managed files
// This ensures consistent behavior between the Downloads root
// and other roots.
int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (doc.isWriteSupported()) {
flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
}
intent.setFlags(flags);
return intent;
}
APK的mimeType和uri如下:
从以上log看出,该隐式intent首先启动了PackageInstaller中的InstallStart,再有InstallStart启动InstallStaging,最后启动PackageInstallerActivity。
我们来看manifest中InstallStart注册的data和action。
/packages/apps/PackageInstaller/AndroidManifest.xml
<activity android:name=".InstallStart"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="package" />
<data android:scheme="content" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
由第一个<intent-filter>标签可知,正好其注册的data和action满足此意图,因而由其响应该事件。