文章目录
一、 ActivityThread 中的 installProvider 方法 ( 创建 ContentProvider 内容提供者 )
二、 installProvider 方法的第三分支分析
三、 ContextImpl 中 createPackageContext 方法分析
四、ContentProvider 中替换 Application 的总结
前置博客 : 【Android 安全】DEX 加密 ( Application 替换 | 分析 ContentProvider 组件中调用 getApplication() 获取的 Application )
一、 ActivityThread 中的 installProvider 方法 ( 创建 ContentProvider 内容提供者 )
在 installProvider 方法中 , 通过 反射创建 ContentProvider ;
// ★ 反射创建 ContentProvider localProvider = (ContentProvider)cl. loadClass(info.name).newInstance();
在 创建 ContentProvider 之后 , 调用了 attachInfo 函数 , 注意此处与 Activity , Service , BrocastReceiver 不同 , 这三个组件创建后调用的是 attach 函数 ;
// XXX Need to create the correct context for this provider. // ★ 创建 ContentProvider 之后 , 调用了 attachInfo 函数 // 注意此处与 Activity , Service , BrocastReceiver 不同 , // 这三个组件创建后调用的是 attach 函数 localProvider.attachInfo(c, info);
这里分析 attachInfo 中的 c 参数 , 也就是 Context 上下文的获取过程 :
声明空的 Context c 对象 ,
// ★ 该上下文对象很重要 Context c = null;
获取 ApplicationInfo 信息 ApplicationInfo ai , 即 AndroidManifest.xml 中配置的 application 节点信息
// 该 ApplicationInfo 是 AndroidManifest.xml 中配置的 application 节点信息 ApplicationInfo ai = info.applicationInfo;
进行如下三个分支的判定 :
分支一 : if (context.getPackageName().equals(ai.packageName)) : 在应用中配置的代理 Application 包名与真实 Application 包名都是相等的 ;
分之二 : else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) : 与分支一类似 , 也是要求包名相等 ;
分支三 : 上面两个分支没有命中 , 就执行第三个分支 ;
// ★ 该上下文对象很重要 Context c = null; // 该 ApplicationInfo 是 AndroidManifest.xml 中配置的 application 节点信息 ApplicationInfo ai = info.applicationInfo; // 该 context 是 ProxyApplication , 代理 Application if (context.getPackageName().equals(ai.packageName)) { // 在应用中配置的代理 Application 包名与真实 Application 包名都是相等的 // 该分支是命中的 c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { // 该分支中 mInitialApplication 就是 Context context 参数 , 肯定不为空 // 该分支无法命中 c = mInitialApplication; } else { // 上述两个分支都无法命中 , 才进入该分支 // 需要将代理 Application 的包名 与 真实应用的包名设置成不同的 // 此时上面两个分支都无法命中 try { c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { // Ignore } }
上面的分支一 与 分支二 都是将 代理 Application 分支 , 因此必须要命中第三个分支 ;
如果将 代理 Application 的 getPackageName() 获取包名的方法返回空 , 此时肯定无法命中前两个分支 , 只能命中第三分支 ;
相关代码示例 :
public final class ActivityThread { /** * Installs the provider. * * Providers that are local to the process or that come from the system server * may be installed permanently which is indicated by setting noReleaseNeeded to true. * Other remote providers are reference counted. The initial reference count * for all reference counted providers is one. Providers that are not reference * counted do not have a reference count (at all). * * This method detects when a provider has already been installed. When this happens, * it increments the reference count of the existing provider (if appropriate) * and returns the existing provider. This can happen due to concurrent * attempts to acquire the same provider. */ private ContentProviderHolder installProvider(Context context, ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { // ★ 声明 ContentProvider ContentProvider localProvider = null; IContentProvider provider; if (holder == null || holder.provider == null) { if (DEBUG_PROVIDER || noisy) { Slog.d(TAG, "Loading provider " + info.authority + ": " + info.name); } // 该上下文对象很重要 Context c = null; ApplicationInfo ai = info.applicationInfo; // 该 context 是 ProxyApplication , 代理 Application if (context.getPackageName().equals(ai.packageName)) { // 在应用中配置的代理 Application 包名与真实 Application 包名都是相等的 // 该分支是命中的 c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { // 该分支中 mInitialApplication 就是 Context context 参数 , 肯定不为空 // 该分支无法命中 c = mInitialApplication; } else { // 上述两个分支都无法命中 , 才进入该分支 // 需要将代理 Application 的包名 与 真实应用的包名设置成不同的 // 此时上面两个分支都无法命中 try { c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { // Ignore } } if (c == null) { Slog.w(TAG, "Unable to get context for package " + ai.packageName + " while loading content provider " + info.name); return null; } try { final java.lang.ClassLoader cl = c.getClassLoader(); // ★ 反射创建 ContentProvider localProvider = (ContentProvider)cl. loadClass(info.name).newInstance(); provider = localProvider.getIContentProvider(); if (provider == null) { Slog.e(TAG, "Failed to instantiate class " + info.name + " from sourceDir " + info.applicationInfo.sourceDir); return null; } if (DEBUG_PROVIDER) Slog.v( TAG, "Instantiating local provider " + info.name); // XXX Need to create the correct context for this provider. // ★ 创建 ContentProvider 之后 , 调用了 attachInfo 函数 // 注意此处与 Activity , Service , BrocastReceiver 不同 , // 这三个组件创建后调用的是 attach 函数 localProvider.attachInfo(c, info); } catch (java.lang.Exception e) { return null; } } else { } return retHolder; } }
参考路径 : frameworks/base/core/java/android/app/ActivityThread.java