Android 框架接口抽取

  1. 目的:
  2. 思路:
    1. 2、直接实例化类(已应用,简单测试Okay)

目的:

逻辑处理与framework路径各模块相互依赖的yunovo-framework源码参与Android编译生成特定可用的yunovo-framework.jar。


思路:

###1、使用ClassLoader机制,依据类描述索引并加载相应的实例(未应用)
MTK 集成自有的一套类加载机制,以PathClassLoader类方式加载,framework中各jar模块源码以classload方式调用相应的抽象接口,具体的接口实现处以apk模块源码的方式集成;

如:frameworks/base/core/java/com/android/internal/app/ResolverActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mRCSePriorityExt = MPlugin.createInstance(IRCSePriorityExt.class.getName(), ResolverActivity.this);
Log.d(TAG , "RCSe Plugin initiated " + mRCSePriorityExt);
if (mRCSePriorityExt != null) {
for (ResolveInfo info : currentResolveList) {
ApplicationInfo applicationInfo = info.activityInfo.applicationInfo;
if (applicationInfo.packageName.equals("com.orangelabs.rcs"))
{
Log.d(TAG, "rebuild list after sort");
currentResolveList.remove(info);
currentResolveList.add(0, info);
break;
}
}
}

通用接口模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.mediatek.common.media;

import java.util.ArrayList;
//import android.widget.ActivityChooserModel.ActivityResolveInfo;
//import com.android.internal.app.ResolverActivity.DisplayResolveInfo;

public interface IRCSePriorityExt {
/**
* Sort the list according to the new rcse option.
* @return
*/
public int sortTheListForRCSe(ArrayList<String> defaultList);

//public int sortTheListForRCSe(ArrayList<String> defaultList);
}

最终实现处:
vendor/mediatek/proprietary/frameworks/base/packages/FwkPlugin/src/com/mediatek/op/media/DefaultRCSePriority.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.mediatek.op.media;
import android.content.Context;
import android.util.Slog;

import com.mediatek.common.PluginImpl;
import com.mediatek.common.media.IRCSePriorityExt;

import java.util.ArrayList;

@PluginImpl(interfaceName="com.mediatek.common.media.IRCSePriorityExt")
public class DefaultRCSePriority implements IRCSePriorityExt
{
private static final String TAG = "DefaultRCSePriority";

public DefaultRCSePriority() {
Slog.i(TAG, "Constructor default called");
}

public DefaultRCSePriority(ArrayList<String> defaultList) {
Slog.i(TAG, "Constructor with parametres as list");

}

public DefaultRCSePriority(Context context) {
Slog.i(TAG, " Constructor called with argument context");
}

public int sortTheListForRCSe(ArrayList<String> defaultList) {
Slog.i(TAG, "sortTheListForRCSe.");
return -1;
}

}

参考MTK的做法,在实际测试过程中,在某些带参数的构造代码块中,MPlugin.createInstance getConstructor不成功,即使在内置的MTK相关代码,根据log观察也同样抛出相应的异常Exception occurs when using constructor with Context:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if (context != null) {
mPluginloader = getPathClassLoader(pi.getApkName(), context.getClassLoader());
} else {
mPluginloader = getPathClassLoader(pi.getApkName(), ClassLoader.getSystemClassLoader().getParent());
}
Log.d(TAG, "Init PathClassLoader successfully : " + mPluginloader);

mPluginClazz = mPluginloader.loadClass(pi.getImplementationName());
Log.d(TAG, "Load class : " + pi.getImplementationName() + " successfully");

if (context != null) {
mPluginContext = context.createPackageContext(pi.getPackageName(), 3);
Log.d(TAG, "Create PackageContext successfully : " + mPluginContext);
try {
Constructor constructor = mPluginClazz.getConstructor(new Class[] { Context.class });
Log.d(TAG, "Create constructor with context successfully : " + constructor);
return constructor.newInstance(new Object[] { mPluginContext });
} catch (NoSuchMethodException e) {
Log.d(TAG, "Exception occurs when using constructor with Context");
} catch (InvocationTargetException e) {
Log.e(TAG, "Exception occurs when execute constructor with Context", e);
}
}

此模式暂时未跟踪到具体的原因,猜想可能是获取到的PathClassLoader不一致,后续闲时待深入。

(20170625)

context的父classloader 包含的路径找不到对应的类,另,无构造带context参数的不需要传参数context。

目前已应用,另,xx-common.jar及xx-framework.jar加入BOOTCLASSPATH中,不需要单独classsload相应的路径,直接getClass().getClassLoader().loadClass(clsPath);

2、直接实例化类(已应用,简单测试Okay)

相当于装载相应的lib,不同的jar之间源码实例化类引用,如:

frameworks/base/core/java/android/app/ContextImpl.java

1
2
3
4
5
6
7
8
9
10
11
// wilber:customize #{
if(YOcUtils.supportCustom()) {
// IYOcContextImplExt mYOcContextExt = MPlugin.createInstance(IYOcContextImplExt.class.getName());
IYOcContextImplExt mYOcContextExt = new YOcContextImplExt();
if(null != mYOcContextExt) {
File[] files = mYOcContextExt.getExternalFilesDirs(this);
if(null != files) {
return files;
}
}
}

YOcContextImplExt,IYOcContextImplExt位于xx_framework.jar

此时编译的问题出现了:framework源码编译依赖xx_framework jar,xx_framework源码编译依赖framework jar,无论如何,都需要所依赖的jar;

目前LP的做法是,参考Eclipse IDE引用方式,先拿到已编译好无依赖的framework.jar,做为xx_framework源码的库引用,最终framework源码与yunovo源码一同编译;

刚开始编译方式一直会出错,处于一种循环依赖的现象,提示

1
make: *** No rule to make target `out/target/common/obj/JAVA_LIBRARIES/xx-framework_intermediates/classes.jar', needed by `out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar'.  Stop.

经XD指点,参考framework的Android.mk写法 ,加入标识编译即可。

1
LOCAL_NO_STANDARD_LIBRARIES := true

目前使用暂时未见其它异常。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 wilber_bai@hotmail.com

文章标题:Android 框架接口抽取

文章字数:958

本文作者:风沉殇史

发布时间:2017-12-12, 12:12:12

最后更新:2020-01-03, 17:32:42

原始链接:http://wilber.win/posts/423323c0/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏