Intent
关于Intent我们都知道他是各个组件,进程之间的通信纽带,Android系统也是通过Intent来查找软件中的对应的组件,并且进行通信。
我们知道在系统启动之后,系统会自动注册各种服务,WindowManagerService和ActivityManagerService就在其中,另外,一个和Intent息息相关的服务也被注册了,这个服务就是PackageManagerService,这个服务主要功能就是解析AndroidMainnifest.xml文件中的APP相关的信息,获取信息完成之后构建项目的信息树。
我们看下PackageManagerService的构造函数:
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { //代码省略 synchronized (mInstallLock) { // writer synchronized (mPackages) { //获取/data目录 File dataDir = Environment.getDataDirectory(); mAppDataDir = new File(dataDir, "data"); //获取第三方应用安装目录 /data/app mAppInstallDir = new File(dataDir, "app"); //代码省略 File frameworkDir = new File(Environment.getRootDirectory(), "framework"); //加载FrameWork资源 alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk"); //加载核心库 alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar"); //省略代码 // 获取系统APP安装路径 File systemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver( systemAppDir.getPath(), OBSERVER_EVENTS, true, false); mSystemInstallObserver.startWatching(); //扫描系统APP安装路径 scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); //省略代码 //非核心应用 if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); mAppInstallObserver = new AppDirObserver( mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false); mAppInstallObserver.startWatching(); //扫描第三方APP安装路径 scanDirLI(mAppInstallDir, 0, scanMode, 0); //代码省略 } else { mAppInstallObserver = null; mDrmAppInstallObserver = null; } //代码省略 } // synchronized (mPackages) } // synchronized (mInstallLock) }
代码又臭又长,省略了部分,我们只要明白在构造函数里面PMS做了几件事:
- 加载了系统已经安装的APK
- 加载了FrameWork与核心库
- 扫描了指定目录下的apk文件并进行解析
上面代码中有个很重要的函数就是扫描第三方的APP安装路径即:scanDirLI函数,我们去看下具体实现:
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { //获取目录下的所有文件 String[] files = dir.list(); if (files == null) { Log.d(TAG, "No files in app dir " + dir); return; } if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Scanning app dir " + dir + " scanMode=" + scanMode + " flags=0x" + Integer.toHexString(flags)); } int i; //解析目录下的所有apk文件 for (i=0; i<files.length; i++) { File file = new File(dir, files[i]); if (!isPackageFilename(files[i])) { // Ignore entries which are not apk's //不是apk文件,忽略 continue; } //解析apk文件 PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); // Don't mess around with apps in system partition. if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) { // Delete the apk Slog.w(TAG, "Cleaning up failed install of " + file); file.delete(); } } }
这个方法主要的功能就是扫描指定目录下的apk文件,然后通过scanPackageLIb函数进行解析。所以这个方法的主要功能在scanPackageLIb函数中,我们去查看这个代码:
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); if (pkg == null) { mLastScanError = pp.getParseError(); return null; } PackageSetting ps = null; PackageSetting updatedPkg; // reader synchronized (mPackages) { // Look to see if we already know about this package. String oldName = mSettings.mRenamedPackages.get(pkg.packageName); if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) { // This package has been renamed to its original name. Let's // use that. ps = mSettings.peekPackageLPr(oldName); } // If there was no original package, see one for the real package name. if (ps == null) { ps = mSettings.peekPackageLPr(pkg.packageName); } // Check to see if this package could be hiding/updating a system // package. Must look for it either under the original or real // package name depending on our state. updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName); if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg); } // First check if this is a system package that may involve an update if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { if (ps != null && !ps.codePath.equals(scanFile)) { // The path has changed from what was last scanned... check the // version of the new path against what we have stored to determine // what to do. if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath); if (pkg.mVersionCode < ps.versionCode) { // The system package has been updated and the code path does not match // Ignore entry. Skip it. Log.i(TAG, "Package " + ps.name + " at " + scanFile + " ignored: updated version " + ps.versionCode + " better than this " + pkg.mVersionCode); if (!updatedPkg.codePath.equals(scanFile)) { Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : " + ps.name + " changing from " + updatedPkg.codePathString + " to " + scanFile); updatedPkg.codePath = scanFile; updatedPkg.codePathString = scanFile.toString(); // This is the point at which we know that the system-disk APK // for this package has moved during a reboot (e.g. due to an OTA), // so we need to reevaluate it for privilege policy. if (locationIsPrivileged(scanFile)) { updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED; } } updatedPkg.pkg = pkg; mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; return null; } else { // The current app on the system partion is better than // what we have updated to on the data partition; switch // back to the system partition version. // At this point, its safely assumed that package installation for // apps in system partition will go through. If not there won't be a working // version of the app // writer synchronized (mPackages) { // Just remove the loaded entries from package lists. mPackages.remove(ps.name); } Slog.w(TAG, "Package " + ps.name + " at " + scanFile + "reverting from " + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } synchronized (mPackages) { mSettings.enableSystemPackageLPw(ps.name); } } } } if (updatedPkg != null) { // An updated system app will not have the PARSE_IS_SYSTEM flag set // initially parseFlags |= PackageParser.PARSE_IS_SYSTEM; // An updated privileged app will not have the PARSE_IS_PRIVILEGED // flag set initially if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { parseFlags |= PackageParser.PARSE_IS_PRIVILEGED; } } // Verify certificates against what was last scanned if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) { Slog.w(TAG, "Failed verifying certificates for package:" + pkg.packageName); return null; } /* * A new system app appeared, but we already had a non-system one of the * same name installed earlier. */ boolean shouldHideSystemApp = false; if (updatedPkg == null && ps != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) { /* * Check to make sure the signatures match first. If they don't, * wipe the installed application and its data. */ if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { if (DEBUG_INSTALL) Slog.d(TAG, "Signature mismatch!"); deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false); ps = null; } else { /* * If the newly-added system app is an older version than the * already installed version, hide it. It will be scanned later * and re-added like an update. */ if (pkg.mVersionCode < ps.versionCode) { shouldHideSystemApp = true; } else { /* * The newly found system app is a newer version that the * one previously installed. Simply remove the * already-installed application and replace it with our own * while keeping the application data. */ Slog.w(TAG, "Package " + ps.name + " at " + scanFile + "reverting from " + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } } } } // The apk is forward locked (not public) if its code and resources // are kept in different files. (except for app in either system or // vendor path). // TODO grab this value from PackageSettings if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { if (ps != null && !ps.codePath.equals(ps.resourcePath)) { parseFlags |= PackageParser.PARSE_FORWARD_LOCK; } } String codePath = null; String resPath = null; if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) { if (ps != null && ps.resourcePathString != null) { resPath = ps.resourcePathString; } else { // Should not happen at all. Just log an error. Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName); } } else { resPath = pkg.mScanPath; } codePath = pkg.mScanPath; // Set application objects path explicitly. setApplicationInfoPaths(pkg, codePath, resPath); // Note that we invoke the following method only if we are about to unpack an application PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); /* * If the system app should be overridden by a previously installed * data, hide the system app now and let the /data/app scan pick it up * again. */ if (shouldHideSystemApp) { synchronized (mPackages) { /* * We have to grant systems permissions before we hide, because * grantPermissions will assume the package update is trying to * expand its permissions. */ grantPermissionsLPw(pkg, true); mSettings.disableSystemPackageLPw(pkg.packageName); } } return scannedPkg; }
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); //解析apk包 final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags); if (pkg == null) { mLastScanError = pp.getParseError(); return null; } //代码省略 //解析apk包中的Activity,Service等组件 PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); //代码省略 return scannedPkg; }
这个方法做了下面几件事情:
- 创建一个包解析器PackageParser
- 通过包解析器解析apk包
- 解析了apk包中的Activity,Service等组件
从上面的代码可以看到,解析apk包的重要的功能是PackageParser下的parsePackage函数,我们追踪这个函数,看看具体实现:
private Package parsePackage( Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { AttributeSet attrs = parser; mParseInstrumentationArgs = null; mParseActivityArgs = null; mParseServiceArgs = null; mParseProviderArgs = null; //解析到AndroidMainnifest.xml的包名 //代码省略 //构建Package对象 final Package pkg = new Package(pkgName); boolean foundApp = false; //获取AndroidMainnifest.xml文件中的VersionCode,VersionName等参数 TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifest); pkg.mVersionCode = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_versionCode, 0); pkg.mVersionName = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_versionName, 0); if (pkg.mVersionName != null) { pkg.mVersionName = pkg.mVersionName.intern(); } String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { String nameError = validateName(str, true); if (nameError != null && !"android".equals(pkgName)) { outError[0] = "<manifest> specifies bad sharedUserId name \"" + str + "\": " + nameError; mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; return null; } pkg.mSharedUserId = str.intern(); pkg.mSharedUserLabel = sa.getResourceId( com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); } sa.recycle(); pkg.installLocation = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_installLocation, PARSE_DEFAULT_INSTALL_LOCATION); pkg.applicationInfo.installLocation = pkg.installLocation; /* Set the global "forward lock" flag */ if ((flags & PARSE_FORWARD_LOCK) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK; } /* Set the global "on SD card" flag */ if ((flags & PARSE_ON_SDCARD) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; } // Resource boolean are -1, so 1 means we don't know the value. int supportsSmallScreens = 1; int supportsNormalScreens = 1; int supportsLargeScreens = 1; int supportsXLargeScreens = 1; int resizeable = 1; int anyDensity = 1; //解析AndroidMainnifest.xml中的元素 int outerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals("application")) { //代码省略 //解析Application标签,Activity和Service的所在 if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { return null; } } else if (tagName.equals("uses-permission")) { //解析用户权限标签 if (!parseUsesPermission(pkg, res, parser, attrs, outError)) { return null; } } //其他标签省略~很多,常见的两个在上面了 } //省略代码 return pkg; }
这个上面可以看到做的几件事情:
- 解析包名
- 构建Package对象
- 解析AndroidMainnifest.xml中的各个标签
我们在上面的代码表现出来两个解析标签的函数,我们找到其中一个就是application的好了,我们发现具体解析application的函数是parseApplication函数,我们跟踪这个函数,看看具体实现:
private boolean parseApplication(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException, IOException { //应用信息 final ApplicationInfo ai = owner.applicationInfo; //包名 final String pkgName = owner.applicationInfo.packageName; //获取Application的标签 TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestApplication); //获取应用名 String name = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_name, 0); if (name != null) { ai.className = buildClassName(pkgName, name, outError); if (ai.className == null) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } } //代码省略 //获取程序的icon,logo等参数 ai.icon = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); ai.logo = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); ai.banner = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_banner, 0); ai.theme = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); ai.descriptionRes = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_description, 0); //代码省略 final int innerDepth = parser.getDepth(); int type; //获取Application下的所有子元素 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } //获取标签名 String tagName = parser.getName(); //解析Activity if (tagName.equals("activity")) { Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false, hardwareAccelerated); if (a == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.activities.add(a); //解析receiver } else if (tagName.equals("receiver")) { Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false); if (a == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.receivers.add(a); } //解析其他的例如Service等~代码省略 return true; }
这个代码做的一个非常普通的xml解析,并且会根据不同的标签使用不同的解析方法例如解析Activity的parseActivity和解析service的parseService他们都回返回一个向右的实例,并把这个实例添加到Package对象列表中去 。
好了,解析apk的方法我们算是走了一遍了,回到调用这个方法的最初点:就是PackageManagerService类中的scanPackageLI方法,在这个方法里我们看到最后调用了一个和scanPackageLI同名的但是不同参数的函数scanPackageLI(PackageParser.Package pkg,int parseFlags, int scanMode, long currentTime, UserHandle user) 这个函数的我们看下主要实现过程:
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, long currentTime, UserHandle user) { //代码省略 int N = pkg.providers.size(); StringBuilder r = null; int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); p.info.processName = fixProcessName(pkg.applicationInfo.processName, p.info.processName, pkg.applicationInfo.uid); mProviders.addProvider(p); p.syncable = p.info.isSyncable; if (p.info.authority != null) { String names[] = p.info.authority.split(";"); p.info.authority = null; for (int j = 0; j < names.length; j++) { if (j == 1 && p.syncable) { // We only want the first authority for a provider to possibly be // syncable, so if we already added this provider using a different // authority clear the syncable flag. We copy the provider before // changing it because the mProviders object contains a reference // to a provider that we don't want to change. // Only do this for the second authority since the resulting provider // object can be the same for all future authorities for this provider. p = new PackageParser.Provider(p); p.syncable = false; } if (!mProvidersByAuthority.containsKey(names[j])) { mProvidersByAuthority.put(names[j], p); if (p.info.authority == null) { p.info.authority = names[j]; } else { p.info.authority = p.info.authority + ";" + names[j]; } if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Registered content provider: " + names[j] + ", className = " + p.info.name + ", isSyncable = " + p.info.isSyncable); } } else { PackageParser.Provider other = mProvidersByAuthority.get(names[j]); Slog.w(TAG, "Skipping provider name " + names[j] + " (in package " + pkg.applicationInfo.packageName + "): name already used by " + ((other != null && other.getComponentName() != null) ? other.getComponentName().getPackageName() : "?")); } } } if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(p.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r); } N = pkg.services.size(); r = null; for (i=0; i<N; i++) { PackageParser.Service s = pkg.services.get(i); s.info.processName = fixProcessName(pkg.applicationInfo.processName, s.info.processName, pkg.applicationInfo.uid); mServices.addService(s); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(s.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r); } N = pkg.receivers.size(); r = null; for (i=0; i<N; i++) { PackageParser.Activity a = pkg.receivers.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mReceivers.addActivity(a, "receiver"); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r); } N = pkg.activities.size(); r = null; for (i=0; i<N; i++) { PackageParser.Activity a = pkg.activities.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mActivities.addActivity(a, "activity"); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r); } //代码省略 if (pkg.protectedBroadcasts != null) { N = pkg.protectedBroadcasts.size(); for (i=0; i<N; i++) { mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i)); } } pkgSetting.setTimeStamp(scanFileTime); } return pkg; }
这个函数主要做了一件事情,就是把在parsePackage中获取的apk配置列表读取出来,并加入到对应的mActivities,mServices等列表中去。到了这一步,整个已经安装apk的信息树已经建立了,每个apk的应用包名,应用名称,图标等等都已经在系统中有存储,当Intent跳转到某个Activity中的时候Intent就会在这个信息书中的列表中查找,符合条件的组件就会启动。
这样的话就可以通过Intent将各个组件连接到一起,使Android系统成为一个组件可复用的系统。