首页 > 代码库 > Kitkat的加密功能对应用做了什么?
Kitkat的加密功能对应用做了什么?
一. 加密后,系统服务针对加密功能做了什么?
最先启动的是SystemServer,调用ServerThread的initAndLoop()方法,开始启动系统的其他的服务。
在该文件中搜索“crypt”,得到如下内容:
1.
private static final String ENCRYPTING_STATE = "trigger_restart_min_framework"; private static final String ENCRYPTED_STATE = "1";
从常量字符串的英文可以看出来是在手机加密完毕后重启进入最小framework系统的状态。
2.
Slog.i(TAG, "Package Manager"); // Only run "core" apps if we're encrypting the device. String cryptState = SystemProperties.get("vold.decrypt"); if (ENCRYPTING_STATE.equals(cryptState)) { Slog.w(TAG, "Detected encryption in progress - only parsing core apps"); onlyCore = true; } else if (ENCRYPTED_STATE.equals(cryptState)) { Slog.w(TAG, "Device encrypted - only parsing core apps"); onlyCore = true; }
log中已经注明了,对于Package Manager来说,在加密状态下,只加载核心(core)应用,那么什么样的应用算是core应用呢?这也是本文重点关注的内容。我们在接下来的内容中进行探索。
接着看代码,vold.decrypt在第一次加密重启时,设置为” trigger_restart_min_framework“, 当加密完毕后重启时,就会被设置为”1”。此时onlyCore被设置为true。
3
. pm = PackageManagerService.main(context, installer, factoryTest != SystemServer.FACTORY_TEST_OFF, onlyCore); try { firstBoot = pm.isFirstBoot(); } catch (RemoteException e) { }
调用PackageManagerService的静态方法main()开始创建PackageManagerService的对象,并做一些初始化工作。可以看到,main()方法的最后一个参数就是上一步中设置为true的onlyCore.看来应该是在main()方法中使用了onlyCore的值。
4. PackageManagerService.java
public static final IPackageManager main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); ServiceManager.addService("package", m); return m; }
main()方法中使用onlyCore传入了PackageManagerService的构造方法中。
接下来是对PackageManagerService中对于onlyCore的分析:
5.
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { ……. mOnlyCore = onlyCore; …… mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore); ….. }
首先给mOnlyCore赋值为onlyCore,这里为true,那么我们以后看到mOnlyCore和onlyCore都认为是ture就可以了。尽管Settings调用的readLPw()方法中传入了mOnlyCore,但是在该方法中并没有使用。
6. 接下来的内容,就是我们这里的重点了。
对于PackageManagerService来说,在构造方法中需要对已经安装的应用进行扫描,进行重新安装的操作,针对非正常关机等情况,对系统中的应用信息进行修复等操作。
Android手机安装应用的路径主要由以下代码所示:
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay" File frameworkDir = new File(Environment.getRootDirectory(), "framework"); File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); File systemAppDir = new File(Environment.getRootDirectory(), "app"); File vendorAppDir = new File("/vendor/app");
上述代码标识了需要扫描的路径:
/vendor/overlay
/system/framework/
/system/priv-app
/system/app
/vender/app
对于这部分内容,值得说的是/system/priv-app目录是Kitkat以后才开始使用的,将一些以前放置到/system/app目录下的系统应用放置到该目录下。没有看到有什么特别大的区别。
7. 需要扫描以上路径中的安装文件,然后解析文件,进行安装操作。都会调用一个Pms的一个非常重要方法scanDirLI(),如接下来的代码所示(由于太长,都是一个模式,我们拿出一个来分析,这里选择/system/app目录):
// Collect ordinary system packages. File systemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver( systemAppDir.getPath(), OBSERVER_EVENTS, true, false); mSystemInstallObserver.startWatching(); scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
首先创建/system/app目录,当然如果已经创建了,就获得该文件对象,然后设置一个AppDirObserver,也就是当该目录下的apk应用变更的时候,就会触发这个监听,让后进行一系列的重新安装操作。
最明显的就是,我们编译的系统应用,直接adb push xxx.apk/system/app 操作的时候,被替换的xxx.apk就会发生变化,此时就会触发这个AppDirObserver.接下来mSystemInstallObserver监听器的startWatching()方法,开始监听。
终于到了关键方法scanDirLI()了,它就是真正扫描这个目录,并解析出apk包,并安装的执行者。这里出入的参数可以看出PackageParser.PARSE_IS_SYSTEM|PackageParser.PARSE_IS_SYSTEM_DIR,是系统应用和系统目录,我们知道/system/app目录下的都是系统应用,第三方的应用是不能安装到该目录下的。
8.我们先从PackageManagerService的构造方法中出来,进入到scanDirLI()方法中:
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { String[] files = dir.list(); …… for (i=0; i<files.length; i++) { File file = new File(dir, files[i]); …… PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); ….. } }
该方法中,获得传入的参数dir,得到该目录下的文件列表,也就是apk的文件列表,然后遍历该文件列表,调用scanPackageLI()方法,将apk解析成一个个的PackageParser.Package对象。
9.接着看scanPackageLI()方法中做了些什么?
需要注意的是,Pms中有两个同名的scanPackageLI()方法,签名不同。我们这里是调用第一个参数是File类型的scanPackageLI()方法。
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode, long currentTime, UserHandle user) { mLastScanError = PackageManager.INSTALL_SUCCEEDED; String scanPath = scanFile.getPath(); if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath); parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(scanPath); pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0); }
我们看到红色代码中使用了mOnlyCore,是给PackageParser类型的pp设置的,接着调用pp的parsePacakge()方法开始解析apk安装包了。
10.
public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags, boolean trustedOverlay) { ……. try { // XXXX todo: need to figure out correct configuration. pkg = parsePackage(res, parser, flags, trustedOverlay, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; } ……. }
调用同名方法parsePackage(),第一个参数是Resources。我们接着看该方法的内容:
11.
private Package parsePackage( Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay, String[] outError) throws XmlPullParserException, IOException { AttributeSet attrs = parser; …… if (mOnlyCoreApps) { boolean core = attrs.getAttributeBooleanValue(null, "coreApp", false); if (!core) { mParseError = PackageManager.INSTALL_SUCCEEDED; return null; } } …… }
终于到正题了,这里看到如果mOnlyCoreApps为true的时候,然后获取apk应用的一个名字为“coreApp”的属性的值,该值是一个boolean值,如果没有设置该属性值,这里给了一个默认值false。
这里本来就是行扫描AndroidManifest.xml中的属性值,所以”coreApp”也是在AndroidManifest.xml中设置的
图1 kitkat工程中AndroidManifest.xml中设置’coreApp”属性的apk目录
从上图中可以看出是“coreApp”的apk有framework-res.apk,DefaultContainerService.apk(存储相关), FakeOemFeatures.apk,InputDevices.apk, Keyguard.apk(锁屏),ProxyHandler.apk,SettingsProvider.pak,Shell.apk,SystemUI.apk,Dialer.apk(由于InCallUi会被编译到Dialer.apk中),Settings.apk,LatinIME.apk, TelephonyProvider.apk, TeleService.apk.移动有15个coreApp。
但是实际的项目中,可能没有FakeOemFeatures.apk,该apk应该是最新添加的。
除了这15个应用以外其他的,应用core为false,进入if 的true分支,设置mParseError 为PackageManager.INSTALL_SUCCEEDED,并返回null,也就是说,当在onlyCore的模式下,非coreApp直接设置状态为已经解析完毕,然后返回null,表示该apk中没有解析出内容。
这里也就解释了,为什么在加密后,进入解锁界面的时候,仅仅有部分应用是可用的。
从这里也可以看出,在此界面,只能使用Latin输入法,可以打电话(Dialer),可以挂载存储设备。设置中的功能还是可用的。因为解锁的界面就属于Settings.apk,类名称是CryptKeeper。
至此,我们已经对Android加密功能对Android应用到底做了些那些区别对待。
Kitkat的加密功能对应用做了什么?