android-plugmgr源代码分析

android-plugmgr是一个Android插件加载框架,它最大的特点就是对插件不需要进行任何约束。关于这个类库的介绍见作者博客,市面上也有一些插件加载框架,但是感觉没有这个好。在这篇文章中,我们将不仅止于原理,对源代码的具体实现进行分析。文章中涉及的代码可从https://github.com/kissazi2/AndroidDemo/tree/master/PlugLoadDemo下载,基于Android Studio 1.2编译。

在正式开始分析源代码之前,我们首先需要有一些动态加载Apk的基础知识。

  • 《Android apk动态加载机制的研究》

    总的说来,为了调用另一个apk中的类,我们就需要用Android中提供的ClassLoader,将不属于宿主Apk中的类加载进来。由于Android中不允许没有在AndroidManifest中声明的Activity被运行,所以我们需要在AndroidManifest中声明一个代理Activity(ProxyActivity).这篇文章中的思路是,在插件的Activity中将这个ProxyActivity传进去,这样代码执行的逻辑是插件Activity的,同时插件Activity也因为ProxyActivity拥有了部分系统资源的访问能力。这里不是指Resource的访问而是Context所拥有的访问其他组件、与服务交互的能力。当然,插件Activity也存在生命周期函数没法被系统调用、无法访问Resource的问题。

  • 《 Android apk动态加载机制的研究(二):资源加载和activity生命周期管理》.

    这篇文章解决资源访问的思路是,通过构造Resource对象及其依赖的AssetManager,将资源重定向到插件Apk,然后Override插件中getResource方法。解决生命周期函数无法调用的方法是在ProxyActivity的每一个生命周期函数调用的时候同时调用插件Activity的对应函数。

从这两篇文章中,我们大致了解了插件动态加载的流程。我们将要分析的android_plugmgr的思路与上面文章中的思路完全不同,它通过将继承关系反转,也就是说宿主Activity中的ProxyActivity去继承插件中的Activity。在startActivity(...)启动这个Activity之前,通过自己实现的ClassLoader去加载这个临时被构造出来的Activity。这个框架不像上面文章介绍的插件加载框架有那么多的限制。

1.先用起来

这个框架只需要在如下面截图中的指定文件夹(一般是sdcard中的Download文件夹)中放入需要动态加载的APK文件,选择对应的图标就可以实现动态加载了.

1、加载插件信息

    @Override
    public void onClick(View v) {
        final String dirText = pluginDirTxt.getText().toString().trim();
        //省略不必要的代码
        new Thread(new Runnable() {
            @Override
            public void run() {
                    Collection<PlugInfo> plugs = plugMgr
                            .loadPlugin(new File(dirText));
                    setPlugins(plugs);
            }
        }).start();
    }

    private void setPlugins(final Collection<PlugInfo> plugs) {
        if (plugs == null || plugs.isEmpty()) {
            return;
        }
        final ListAdapter adapter = new PlugListViewAdapter(this, plugs);
        runOnUiThread(new Runnable() {
            public void run() {
                pluglistView.setAdapter(adapter);
            }
        });
    }

从上面我们看到插件的信息通过文件地址dirText传入,然后由 plugMgr.loadPlugin(new File(dirText))进行apk信息的加载,最终将信息保存在plugInfo的集合。plugMgr是一个PluginManager类型的对象,它定义在android_plugmgr类库中。PlugListViewAdapter(继承自BaseAdapter)就是一个带有PlugInfo的Adatpter而已。

2、点击每一项,加载对应的插件

    private void plugItemClick(int position) {
        PlugInfo plug = (PlugInfo) pluglistView.getItemAtPosition(position);
        plugMgr.startMainActivity(this, plug.getPackageName());
    }

2.类库分析

在了解基本的使用之后,我们看看android_plugmgr中包含什么具体的类。截图中的类所在的包与原作者的类库中的包略有不同,因为要在Android Studio中编译做的小修改。下面罗列出这些类,只为给大家一个模糊的关于这个类库结构,可以尝试着理清他们之间的关系,看不懂就跳过。

  • ActivityClassGenerator: 动态生成 插件Activity子类的工具类
  • ActivityOverider :提供公共方法供自动生成的Activity调用
  • FrameworkClassLoader 框架类加载器(Application 的 classLoder被替换成此类的实例),它主要是对插件、宿主的apk进行分别的处理。
  • LayoutInflaterWrapper :LayoutInflater 包装器,用来替换某些系统布局
  • PluginActivityLifeCycleCallback :插件Activity的生命周期方法回调
  • PluginActivityWrapper :插件Activity的包装类
  • PluginClassLoader :插件类加载器,实现dex文件生成、加载
  • PluginContextWrapper :插件Context包装类
  • PlugInfo :插件信息实体类
  • PluginManager :插件管理类,提供给外部初始化插件apk、启动Activity的公共借口。
  • PluginManifestUtil :插件Manifest信息提取类,除提取Manifest信息外,也包括提取插件apk中lib的类库)
  • PluginPackageManager :这个类库自定义的PackageManager,对PackageManager做了些包装
  • ReflectionUtils :反射工具类,提供一些常用的反射操作。
  • XmlManifestReader : AndroidManifest.xml读取类

3.代码分析

3.1 插件apk信息的加载

从前面的分析中,我们知道要加载插件apk中的信息,我们需要加载插件apk中的组件(Activity、service、brocastreceiver)、用DexClassLoader加载Dex文件中信息、修改Resource类的资源指向。要完成以上操作,我们需要读取插件apk包中的AndroidManifest信息,取出一些必要的内容(不单单是从AndroidManifest.xml,还有插件apk本身)。

之前我们忽略了PluginManager的初始化。它的初始化是在宿主APK的MainActivity中进行的。初始化通过PluginManager.getInstance()→PluginManager.init()进行调用。getInstance()所做的就是获取ApplicationContext然后传给init().


    private void init(Context ctx) {
        Log.i(tag, "init()...");
        context = ctx;
        //plugsout是让DexClassLoader存放它Dex文件的地方,可以先放过
        File optimizedDexPath = ctx.getDir("plugsout", Context.MODE_PRIVATE);
        if (!optimizedDexPath.exists()) {
            optimizedDexPath.mkdirs();
        }
        dexOutputPath = optimizedDexPath.getAbsolutePath();
        dexInternalStoragePath = context
                .getDir("plugins", Context.MODE_PRIVATE);
        //创建plugins用来存放插件apk,以及插件apk中的lib包
        dexInternalStoragePath.mkdirs();
        // 改变classLoader,以便根据是插件apk、还是宿主apk中的类进行特殊处理
        try {
            Object mPackageInfo = ReflectionUtils.getFieldValue(ctx,
                    "mBase.mPackageInfo", true);
            frameworkClassLoader = new FrameworkClassLoader(
                    ctx.getClassLoader());
            // set Application's classLoader to FrameworkClassLoader
            ReflectionUtils.setFieldValue(mPackageInfo, "mClassLoader",
                    frameworkClassLoader, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
        hasInit = true;
    }
    


我们来模拟计算机一步步地执行看看。从"先用起来"那一节,我们知道加载类库会调用androidx.pluginmgr.PluginManager.loadPlugin(...)方法.在这一步里面主要对后面用的到的信息进行加载.从代码里面不管单个还是多个插件都进入PluginManager.buildPlugInfo(...)。


    public Collection<PlugInfo> loadPlugin(final File pluginSrcDirFile)
            throws Exception {
        checkInit();
        if (pluginSrcDirFile == null || !pluginSrcDirFile.exists()) {
            Log.e(tag, "invalidate plugin file or Directory :"
                    + pluginSrcDirFile);
            return null;
        }
        if (pluginSrcDirFile.isFile()) {
            // 如果是文件则尝试加载单个插件,暂不检查文件类型,除apk外,以后可能支持加载其他类型文件,如jar
            PlugInfo one = loadPluginWithId(pluginSrcDirFile, null, null);
            return Collections.singletonList(one);
        }
        // clear all first
        synchronized (this) {
            pluginPkgToInfoMap.clear();
            pluginIdToInfoMap.clear();
        }
        File[] pluginApks = pluginSrcDirFile.listFiles(this);
        if (pluginApks == null || pluginApks.length < 1) {
            throw new FileNotFoundException("could not find plugins in:"
                    + pluginSrcDirFile);
        }
        for (File pluginApk : pluginApks) {
            PlugInfo plugInfo = buildPlugInfo(pluginApk, null, null);
            if (plugInfo != null) {
                savePluginToMap(plugInfo);
            }
        }
        return pluginIdToInfoMap.values();
    }

    /**
     * 初始化插件apk的必要信息
     * @param pluginApk 要加载的APK路径
     * @param pluginId 插件apk的名字(一般是xxx.apk),nullable
     * @param targetFileName 插件apk的名称,nullable
     * @return
     * @throws Exception
     */
    private PlugInfo buildPlugInfo(File pluginApk, String pluginId,
            String targetFileName) throws Exception {
        PlugInfo info = new PlugInfo();
        info.setId(pluginId == null ? pluginApk.getName() : pluginId);

        File privateFile = new File(dexInternalStoragePath,
                targetFileName == null ? pluginApk.getName() : targetFileName);

        info.setFilePath(privateFile.getAbsolutePath());
        //1.把插件apk复制到app_plugins目录下,防止因为意外情况被破坏
        if (!pluginApk.getAbsolutePath().equals(privateFile.getAbsolutePath())) {
            copyApkToPrivatePath(pluginApk, privateFile);
        }

        //2.读取AndroidManifest中的信息
        String dexPath = privateFile.getAbsolutePath();
        PluginManifestUtil.setManifestInfo(context, dexPath, info);

        //3.设置插件加载器
        PluginClassLoader loader = new PluginClassLoader(dexPath,
                dexOutputPath, frameworkClassLoader, info);
        info.setClassLoader(loader);

        //4.重定向Resource对象的资源指向
        try {
            AssetManager am = (AssetManager) AssetManager.class.newInstance();
            am.getClass().getMethod("addAssetPath", String.class)
                    .invoke(am, dexPath);
            info.setAssetManager(am);
            Resources ctxres = context.getResources();
            Resources res = new Resources(am, ctxres.getDisplayMetrics(),
                    ctxres.getConfiguration());
            info.setResources(res);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //5.初始化插件的application,调用它的onCreate()
        if (actFrom != null) {
            initPluginApplication(info, actFrom, true);
        }
        // createPluginActivityProxyDexes(info);
        Log.i(tag, "buildPlugInfo: " + info);
        return info;
    }

这段函数的思路还是很清晰的,其中我们最为感兴趣的是,加载插件apk究竟需要AndroidManifest什么信息?可以预想到Android四大组件肯定是必须的,权限不是必须的。插件apk的所拥有的权限只能宿主apk中AndroidManifest中的,这是Android的安全机制所保证的。进入PluginManifestUtil.setManifestInfo(...)。

    /**
     * 设置跟Manifest有关的信息
     * @param context MainActivity的实例
     * @param apkPath 插件apk的路径
     * @param info 设置了插件apk的Id、FilePath的PlugInfo
     * @throws XmlPullParserException
     * @throws IOException
     */
    static void setManifestInfo(Context context, String apkPath, PlugInfo info)
            throws XmlPullParserException, IOException {
        //1.读取压缩包里面的信息,将AndroidManifest的值读取出来
        ZipFile zipFile = new ZipFile(new File(apkPath), ZipFile.OPEN_READ);
        ZipEntry manifestXmlEntry = zipFile.getEntry(XmlManifestReader.DEFAULT_XML);

        String manifestXML = XmlManifestReader.getManifestXMLFromAPK(zipFile,
                manifestXmlEntry);
        PackageInfo pkgInfo = context.getPackageManager()
                .getPackageArchiveInfo(
                        apkPath,
                        PackageManager.GET_ACTIVITIES
                                | PackageManager.GET_RECEIVERS//
                                | PackageManager.GET_PROVIDERS//
                                | PackageManager.GET_META_DATA//
                                | PackageManager.GET_SHARED_LIBRARY_FILES//

                );

        //2.将插件apk中libs目录下的所有文件复制到app_plugins/插件Id-dir-lib目录下
        File libdir = ActivityOverider.getPluginLibDir(info.getId());
        try {
            if(extractLibFile(zipFile, libdir)){
                pkgInfo.applicationInfo.nativeLibraryDir=libdir.getAbsolutePath();
            }
        } finally {
            zipFile.close();
        }
        //3.设置插件中activity、receiver、service、application等信息
        setAttrs(info, manifestXML);
    }

从这个函数中,我们就完成了对插件apk所需要的信息的加载,需要注意的是,android-plugmgr这版的源代码暂时只支持Activity,Service、Receiver都还是不支持的。

3.2 插件apk中Activity的加载

这部分是这个类库的核心。这个类库之所以能够无约束地调用插件apk中的Activity,依赖的就是依赖倒置,让宿主apk中的ProxyActivity去继承插件apk中特定的Activity。它的做法是利用dexmaker在运行时动态生成代码实现继承,然后将这个子类输出成Dex文件放到/data/data/androidx.plmgrdemo/app_plugsout。最后它就利用DexClassLoader进行加载。

从点击主界面点击每一个插件开始,

    private void plugItemClick(int position) {
        PlugInfo plug = (PlugInfo) pluglistView.getItemAtPosition(position);
        plugMgr.startMainActivity(this, plug.getPackageName());
    }

    public boolean startMainActivity(Context context, String pkgOrId) {
        Log.d(tag, "startMainActivity by:" + pkgOrId);
        //1.根据包名或Apk命,获取plugInfo
        PlugInfo plug = preparePlugForStartActivity(context, pkgOrId);
        if (frameworkClassLoader == null) {
            Log.e(tag, "startMainActivity: frameworkClassLoader == null!");
            return false;
        }
        if (plug.getMainActivity() == null) {
            Log.e(tag, "startMainActivity: plug.getMainActivity() == null!");
            return false;
        }
        if (plug.getMainActivity().activityInfo == null) {
            Log.e(tag,
                    "startMainActivity: plug.getMainActivity().activityInfo == null!");
            return false;
        }
        //2.这里很关键,三个参数分别是插件的包名、将要加载的插件Activity的名称,这是为了后面能正确地根据
        //Activity或其他普通类是宿主的还是插件的,进行分别处理
        String className = frameworkClassLoader.newActivityClassName(
                plug.getId(), plug.getMainActivity().activityInfo.name);
        //还记得之前贴的代码中(3.1中buildPlugInfo函数),我们提到的application中的classLoader被替换
        //成FrameworkClassloader
        context.startActivity(new Intent().setComponent(new ComponentName(
                context, className)));
        return true;
    }
    

上面代码就是插件加载Activity的整个过程,然而我们漏掉了插件Activity的加载流程,以及特定的Activity怎么被ProxyActivity继承的过程。接下来分析这个类库中自定义的FrameworkClassloader加载特定类的过程。在上面代码context.startActivity(...)中会对将要start的Activity进行加载,也就是调用ClassLoader进行加载,由于我们已经将宿主apk中application的默认Classloader替换成了FrameworkClassloader,所以在context.startActivity(...)的过程中会调用FrameworkClassLoader.loadClass(...)。上一个流程中调用了FrameworkClassloader.newActivityClassName(...),主要为现在插件apk中Activity的加载埋下伏笔。

    /**
     * 1.用actName记录真正要加载的插件apk中的Activity
     * 2.返回ActivityOverider.targetClassName来指示后面的处理流程,要加载的是插件Apk中的Activity
     * @param plugId
     * @param actName
     * @return
     */
    String newActivityClassName(String plugId, String actName) {
        this.plugId = plugId;
        this.actName = actName;
        return ActivityOverider.targetClassName;
    }

    protected Class<?> loadClass(String className, boolean resolv)
            throws ClassNotFoundException {
        Log.i("cl", "loadClass: " + className);
        if (plugId != null) {
            String pluginId = plugId;

            PlugInfo plugin = PluginManager.getInstance().getPluginById(
                    pluginId);
            Log.i("cl", "plugin = " + plugin);
            if (plugin != null) {
                try {
                    //这里判断要加载的Activity是否插件apk中的Activity
                    if (className.equals(ActivityOverider.targetClassName)) {
                        // Thread.dumpStack();
                        String actClassName = actName;
                        //这里的Classloader是PluginClassLoader
                        return plugin.getClassLoader().loadActivityClass(
                                actClassName);
                    } else {
                        return plugin.getClassLoader().loadClass(className);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }

        return super.loadClass(className, resolv);
    }
}

看来frameworkClassloader也就是对类的加载进行预处理,真正的处理还在PluginClassLoader.loadActivityClass(...)。

    /**
     * 加载Activity类
     * @param actClassName 将要加载的特定Activity(带包名)
     * @return
     * @throws ClassNotFoundException
     */
    Class<?> loadActivityClass(final String actClassName) throws ClassNotFoundException {
        Log.d(tag, "loadActivityClass: " + actClassName);

        // 在类加载之前检查创建代理的Activity dex文件,以免调用者忘记生成此文件
        File dexSavePath = ActivityOverider.createProxyDex(thisPlugin, actClassName, true);
        ClassLoader actLoader = proxyActivityLoaderMap.get(actClassName);
        if (actLoader == null) {
            actLoader = new DexClassLoader(dexSavePath.getAbsolutePath(), optimizedDirectory,libraryPath, this){
                @Override
                protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
                    Log.d("PlugActClassLoader("+ actClassName+")", "loadClass: " + name);
                    if (ActivityOverider.targetClassName.equals(name)) {
                        Class<?> c = findLoadedClass(name);
                        if (c == null) {
                            Log.d("PlugActClassLoader("+ actClassName+")", "findClass");
                            c = findClass(name);
                        }
                        if (resolve) {
                            resolveClass(c);
                        }
                        return c;
                    }
                    return super.loadClass(name, resolve);
                }
            };
            proxyActivityLoaderMap.put(actClassName, actLoader);
        }
        return actLoader.loadClass(ActivityOverider.targetClassName);
    }

这段函数里面重点就是ActivityOverider.createProxyDex(...)函数。另外,关于为什么 new DexClassLoader(...)的时候要将this(也就是PluginClassLoader)作为parent传入,参考Java ClassLoader基础及加载不同依赖 Jar 中的公共类


static File createProxyDex(PlugInfo plugin, String activity, boolean lazy) {
        //这里savePath = /data/data/androidx.plmgrdemo/app_plugins/app名称.apk-dir/activities/app包名.XXXXActivity.dex
        File savePath = getPorxyActivityDexPath(plugin.getId(), activity);
        createProxyDex(plugin, activity, savePath, lazy);
        return savePath;
    }

    private static void createProxyDex(PlugInfo plugin, String activity, File saveDir,
            boolean lazy) {
        // Log.d(tag + ":createProxyDex", "plugin=" + plugin + "\n, activity="
        // + activity);
        if (lazy && saveDir.exists()) {
            // Log.d(tag, "dex alreay exists: " + saveDir);
            // 已经存在就不创建了,直接返回
            return;
        }
        // Log.d(tag, "actName=" + actName + ", saveDir=" + saveDir);
        try {
            String pkgName = plugin.getPackageName();
            //这里是ProxyActivity继承插件中特定Activity的具体处理
            ActivityClassGenerator.createActivityDex(activity, targetClassName,
                    saveDir, plugin.getId(), pkgName);
        } catch (Throwable e) {
            Log.e(tag, Log.getStackTraceString(e));
        }
    }

    public static void createActivityDex(String superClassName,
            String targetClassName, File saveTo, String pluginId, String pkgName)
            throws IOException {
        byte[] dex = createActivityDex(superClassName, targetClassName,
                pluginId, pkgName);
        if (saveTo.getName().endsWith(".dex")) {
            FileUtil.writeToFile(dex, saveTo);
        } else {
            JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(
                    saveTo));
            jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME));
            jarOut.write(dex);
            jarOut.closeEntry();
            jarOut.close();
        }
    }   

可以看出ActivityClassGenerator.createActivityDex(...)是重点,它利用dexmaker在运行时动态生成代码让ProxyActivity继承插件apk中特定的Activity,当然这个Activity中的生命周期函数肯定要进行一些修改。在看接下来的代码前,你可能需要先了解dexmarker的语法.


    /**
     * 生成Activity的Dex文件
     * @param superClassName
     * @param targetClassName
     * @param pluginId
     * @param pkgName
     * @return
     */
    public static <S, D extends S> byte[] createActivityDex(
            final String superClassName, final String targetClassName,
            final String pluginId, String pkgName) {

        DexMaker dexMaker = new DexMaker();

        TypeId<D> generatedType = TypeId.get('L' + targetClassName.replace('.',
                '/') + ';');

        TypeId<S> superType = TypeId
                .get('L' + superClassName.replace('.', '/') + ';');
        // 声明类
        dexMaker.declare(generatedType, "", PUBLIC | FINAL, superType);
        // 定义字段
        //private static final String _pluginId = @param{pluginId};
        // private AssetManager asm;
        // private Resources res;
        declareFields(dexMaker, generatedType, superType, pluginId,pkgName);
        // 声明 默认构造方法
        declare_constructor(dexMaker, generatedType, superType);

        // 声明 方法:onCreate
        declareMethod_onCreate(dexMaker, generatedType, superType);
        // 声明 方法:public AssetManager getAssets()
        declareMethod_getAssets(dexMaker, generatedType, superType);
        // 声明 方法:public Resources getResources()
        declareMethod_getResources(dexMaker, generatedType, superType);
        /*
         * 声明 方法:startActivityForResult(Intent intent, int requestCode, Bundle
         * options)
         */
        declareMethod_startActivityForResult(dexMaker, generatedType,superType);
        // 声明 方法:public void onBackPressed()
        declareMethod_onBackPressed(dexMaker, generatedType, superType);

        declareMethod_startService(dexMaker, generatedType, superType);
        declareMethod_bindService(dexMaker, generatedType, superType);
        declareMethod_unbindService(dexMaker, generatedType, superType);
        declareMethod_stopService(dexMaker, generatedType, superType);
        // Create life Cycle methods
        declareLifeCyleMethod(dexMaker, generatedType, superType, "onResume");
        declareLifeCyleMethod(dexMaker, generatedType, superType, "onStart");
        declareLifeCyleMethod(dexMaker, generatedType, superType, "onRestart");
        declareLifeCyleMethod(dexMaker, generatedType, superType, "onPause");
        declareLifeCyleMethod(dexMaker, generatedType, superType, "onStop");
        declareLifeCyleMethod(dexMaker, generatedType, superType, "onDestroy");

        declareMethod_attachBaseContext(dexMaker, generatedType, superType);

        declareMethod_getComponentName(dexMaker, generatedType, superType, superClassName);
        declareMethod_getPackageName(dexMaker, generatedType, pkgName);
        declareMethod_getIntent(dexMaker, generatedType, superType);
        declareMethod_setTheme(dexMaker, generatedType, superType);
        // Create the dex Content
        byte[] dex = dexMaker.generate();
        return dex;
    }

传入这个函数的值(以Android-PullToRefresh说明)

  • superClassName = "com.handmark.pulltorefresh.samples.LauncherActivity"
  • targetClassName = "androidx.pluginmgr.PluginActivity"
  • pluginId = "sample-3.0.0.apk"
  • pkgName = "com.handmark.pulltorefresh.samples"

别看这段函数这么长,它也就做了下面的事情(你可以看一下原作者博客看这段生成的代码究竟是怎么样的):

  • 让一个ProxyActivity继承插件Apk中特定的Activity
  • 声明字段
  • 对重要的生命周期方法进行声明,并添加添加ActivityOverride对应的静态方法
  • override访问资源的函数getResource(...)等Activity自身要提供的公共接口

我们以declareMethod_onCreate(dexMaker, generatedType, superType)进行分析


    private static <S, D extends S> void declareMethod_onCreate(
            DexMaker dexMaker, TypeId<D> generatedType, TypeId<S> superType) {
        //
        // 声明 方法:onCreate
        TypeId<Bundle> Bundle = TypeId.get(Bundle.class);
        TypeId<ActivityOverider> ActivityOverider = TypeId
                .get(ActivityOverider.class);

        MethodId<D, Void> method = generatedType.getMethod(TypeId.VOID,
                "onCreate", Bundle);
        Code methodCode = dexMaker.declare(method, PROTECTED);
        // locals
        Local<D> localThis = methodCode.getThis(generatedType);
        Local<Bundle> lcoalBundle = methodCode.getParameter(0, Bundle);
        Local<Boolean> lcoalCreated = methodCode.newLocal(TypeId.BOOLEAN);
        Local<String> pluginId = get_pluginId(generatedType, methodCode);

        // this.mOnCreated = true;
        FieldId<D, Boolean> beforeOnCreate = generatedType.getField(TypeId.BOOLEAN, FIELD_mOnCreated);
        methodCode.loadConstant(lcoalCreated, true);
        methodCode.iput(beforeOnCreate, localThis, lcoalCreated);

        //ActivityOverider.callback_onCreate(str, this);
        MethodId<ActivityOverider, Void> method_call_onCreate = ActivityOverider
                .getMethod(TypeId.VOID, "callback_onCreate", TypeId.STRING,
                        TypeId.get(Activity.class));
        methodCode
                .invokeStatic(method_call_onCreate, null, pluginId, localThis);

        // super.onCreate()
        MethodId<S, Void> superMethod = superType.getMethod(TypeId.VOID, "onCreate",
                Bundle);
        methodCode.invokeSuper(superMethod, null, localThis, lcoalBundle);

        methodCode.returnVoid();
    }

这段函数所做的事情可以用下面的java代码表示

  protected void onCreate(Bundle paramBundle)
  {
    String str = _pluginId;
    this.mOnCreated = true;
    ActivityOverider.callback_onCreate(str, this);
    super.onCreate(paramBundle);
  }

其他函数的声明与此相似,这个类库关于生命周期函数的处理就不如表面看的如此简单,它在实现原有Activity功能的时候,同时提供了用ActivityOverride的回调函数。细细地考虑一下,这点给了我们一个拓展的接口。另外如果什么东西都用dexmark写,那就太烦了。

写在最后

我们的分析就到这里。这个类库目前也就支持Activity、receiver(最新的实验分支支持)而已,对于Service还是不支持的。

拓展阅读

作者:kissazi2 
出处:http://www.cnblogs.com/kissazi2/ 
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载:http://www.cnblogs.com/kissazi2/p/4526055.html

时间: 2024-10-26 06:07:43

android-plugmgr源代码分析的相关文章

Android ArrayMap源代码分析_Android

      分析源码之前先来介绍一下ArrayMap的存储结构,ArrayMap数据的存储不同于HashMap和SparseArray. Java提供了HashMap,但是HashMap对于手机端而言,对空间的利用太大,所以Android提供了SparseArray和ArrayMap.二者都是基于二分查找,所以数据量大的时候,最坏效率会比HashMap慢很多.因此建议数量在千以内比较合适.  一.SparseArray SparseArray对应的key只能是int类型,它不会对key进行装箱操

Android ArrayMap源代码分析

分析源码之前先来介绍一下ArrayMap的存储结构,ArrayMap数据的存储不同于HashMap和SparseArray. Java提供了HashMap,但是HashMap对于手机端而言,对空间的利用太大,所以Android提供了SparseArray和ArrayMap.二者都是基于二分查找,所以数据量大的时候,最坏效率会比HashMap慢很多.因此建议数量在千以内比较合适. 一.SparseArray SparseArray对应的key只能是int类型,它不会对key进行装箱操作.它使用了两

Android菜鸟的成长笔记(5)——Android系统源代码你下载了吗?

原文:Android菜鸟的成长笔记(5)--Android系统源代码你下载了吗? 在上一篇中我们用Android系统源代码分析了我们前面写的代码,有的朋友可能就会问怎么才能下载到Google官方的源代码呢?下面我们通过Git管理工具来对Android系统源代码进行下载.另外为了方便有的朋友下载,我将下载好的各个版本的源码存放到360云盘,云盘下载链接如下: http://yunpan.cn/QDEkq3uFrbvrI (访问密码:968e) 首先下载Git版本管理工具:下载地址:http://c

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析_Android

        在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码.细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现的,但是我们在编写应用程序都是基于Java语言的,那么,我们如何使用Java语言来使用系统的Binder机制来进行进程间通信呢?这就是本文要介绍的Android系统应用程序框架层的用Java语言来实现的Binder接口了.        熟悉Android系统

Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析_Android

     在上一篇文章中,我们分析了Android系统进程间通信机制Binder中的Server在启动过程使用Service Manager的addService接口把自己添加到Service Manager守护过程中接受管理.在这一篇文章中,我们将深入到Binder驱动程序源代码去分析Client是如何通过Service Manager的getService接口中来获得Server远程接口的.Client只有获得了Server的远程接口之后,才能进一步调用Server提供的服务.       

《Android深度探索(卷2):系统应用源代码分析与ROM定制》——第6章,第6.4节分析第一个Android系统应用:计算器

6.4 分析第一个Android系统应用:计算器 Android深度探索(卷2):系统应用源代码分析与ROM定制 本节会分析一个比较简单的Android系统应用:计算器.这个系统应用几乎被包含在所有的ROM中,也是最常用的Android系统应用之一.计算器尽管从功能上看并不复杂,但实际的实现代码还是比较多的,不过大多数代码都用于控制各种效果.布局.历史处理等.这些部分的实现与普通的Android应用没什么不同,所以本节会直接深入计算器的核心:计算表达式.因为不管计算器的外观多绚丽,最终的目的都是

《深入理解Android 5 源代码》——第2章,第2.2节分析Android源代码结构

2.2 分析Android源代码结构 获得Android 5.0源代码后,源代码的全部工程分为以下3个部分. Core Project:核心工程部分,这是建立Android系统的基础,被保存在根目录的各个文件夹中. External Project:扩展工程部分,可以使其他开源项目具有扩展功能,被保存在"external"文件夹中. Package:包部分,提供了Android的应用程序.内容提供者.输入法和服务,被保存在"package"文件夹中. 在本节的内容中

Android应用程序安装过程源代码分析

转自 :http://blog.csdn.net/luoshengyang/article/details/6766010 Android系统在启动的过程中,会启动一个应用程序管理服务PackageManagerService,这个服务负责扫描系统中特定的目录,找到里面的应用程序文件,即以Apk为后缀的文件,然后对这些文件进解析,得到应用程序的相关信息,完成应用程序的安装过程,本文将详细分析这个过程.         应用程序管理服务PackageManagerService安装应用程序的过程,

Android日志系统驱动程序Logger源代码分析

  我们知道,在Android系统中,提供了一个轻量级的日志系统,这个日志系统是以驱动程序的形式实现在内核空间的,而在用户空间分别提供了Java接口和C/C++接口来使用这个日志系统,取决于你编写的是Android应用程序还是系统组件.在前面的文章浅谈Android系统开发中LOG的使用中,已经简要地介绍了在Android应用程序开发中Log的使用方法,在这一篇文章中,我们将更进一步地分析Logger驱动程序的源代码,使得我们对Android日志系统有一个深刻的认识.         既然And

Android应用程序框架层和系统运行库层日志系统源代码分析

    在开发Android应用程序时,少不了使用Log来监控和调试程序的执行.在上一篇文章Android日志系统驱动程序Logger源代码分析中,我们分析了驱动程序Logger的源代码,在前面的文章浅谈Android系统开发中Log的使用一文,我们也简单介绍在应用程序中使Log的方法,在这篇文章中,我们将详细介绍Android应用程序框架层和系统运行库存层日志系统的源代码,使得我们可以更好地理解Android的日志系统的实现.         我们在Android应用程序,一般是调用应用程序框