在Android中利用抽象类对外提供系统接口

需求背景

Android系统定制中,无可避免需要对外提供一些定制化的接口,使app能完成一些定制化需求。之前用过aidl文件和jar用于app和系统同步接口,但效果都不尽人意。aidl文件对接口有顺序要求,不好增删改查,且接口调用的逻辑诡异;jar需要单独编译,且不能够直接看到接口信息,需要反编译。经过一番探索,发现可以让app使用抽象类来调用系统中的接口,该抽象类类似C语言中的.h文件,只描述接口,实际实现类在系统framework中。

示意图如下:

原理介绍

CustomManager.java作为中间桥梁,内容如下:

java 复制代码
public abstract class CustomManager {  
    public static CustomManager getInstance(Context context) {  
        return (CustomManager) context.getSystemService("CustomManager");  
    }  
  
    public abstract String getVersion();  
}

app将CustomManager.java导入到项目中,并import即可使用CustomManager中的接口。

为了app导入CustomManager.java后能顺利编译通过,CustomManager.java中不能使用超出标准api以外的类,但可交由抽象方法中的实现(CustomManagerImpl)或后端CustomManagerService去做。

app导入CustomManager.java后, 先调用CustomManager.getInstance(Context context)获取实例,然后再使用接口,如:

java 复制代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private CustomManager mCustomManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //实例化
        mCustomManager = CustomManager.getInstance(this)

        //调用具体接口
        mCustomManager.getVersion()
    }
}

CustomManagerImpl.java继承了CustomManager.java并实现了在CustomManager.java中定义的接口:

java 复制代码
public class CustomManagerImpl extends CustomManager {
    private final ICustomManager mService;

    public CustomManagerImpl(Context context, ICustomManager service) {
        mService = service;
        mContext = context;
    }

    public String getVersion() {
        try {
            return mService.getVersion();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "unknow";
    }
}

CustomManagerImpl.java由系统端维护,编译进framework.jar, app在调用CustomManager.getInstance(Context context)后会返回一个CustomManagerImpl实例并转换为CustomManager。 为什么会返回一个CustomManagerImpl实例?因为在系统中注册了服务"CustomManager": SystemServiceRegistry:

java 复制代码
registerService("CustomManager", com.so.CustomManagerImpl.class,
        new CachedServiceFetcher<com.so.CustomManagerImpl>() {
            @Override
            public com.so.CustomManagerImpl createService(ContextImpl ctx)
                    throws ServiceNotFoundException {
                IBinder b = ServiceManager.getService("CustomManagerService");
                ICustomManager service = ICustomManager.Stub.asInterface(b);
                return new com.so.CustomManagerImpl(ctx, service);
            }});

因此在app中只要通过一个字符串"CustomManager"即可得到一个在framework中实现的CustomManagerImpl的实例:

java 复制代码
public abstract class CustomManager {
    public static CustomManager getInstance(Context context) {
        return (CustomManager) context.getSystemService("CustomManager");
    }
}

app获得CustomManager实例后,调用其接口,其实都是在调用CustomManagerImpl的接口。 如mCustomManager.getVersion(),其实走的是CustomManagerImpl.getVersion()。

与后端服务CustomManagerService的交互

CustomManagerImpl虽然在framework中实现,但运行时还在app域,受权限等的限制,能调用的系统功能有限,因此我们进一步在系统中新增一个系统级服务CustomManagerService来实现更复杂的功能。CustomManagerImpl通AIDL来与CustomManagerService交互, 新增aidl文件ICustomManager.aidl:

java 复制代码
interface ICustomManager {
    String getVersion();
}

CustomManagerService继承ICustomManager.Stub, 并实现接口:

java 复制代码
public class CustomManagerService extends ICustomManager.Stub {
    public String getVersion() {
       return "V1.0.0";
    }
}

SystemServiceRegistry在注册服务"CustomManager"时, 也将CustomManagerService的Binder引用传给了CustomManagerImpl.mService,所以在CustomManagerImpl.getVersion()中调用了mService.getVersion()即是调用CustomManagerService.getVersion()。

总结

将抽象类做"头文件"来对外提供接口,有维护简单,逻辑明了,可读性强的优点,甚至可以针对不同需求提供不完全的CustomManager.java来实现接口的隐藏。

相关推荐
robotx1 小时前
AOSP设备节点权限添加相关
android
顾林海1 小时前
Android文件系统安全与权限控制:给应用数据上把“安全锁”
android·面试·操作系统
青莲8431 小时前
Android 动画机制完整详解
android·前端·面试
城东米粉儿1 小时前
android 离屏预渲染 笔记
android
未知名Android用户1 小时前
Android自定义 View + Canvas—声纹小球动画
android
清风拂山岗 明月照大江1 小时前
同步与死锁
操作系统
_李小白1 小时前
【Android FrameWork】延伸阅读:AMS 的 handleApplicationCrash
android·开发语言·python
崎岖Qiu2 小时前
【OS笔记38】:设备管理 - I/O 设备原理
笔记·操作系统·os·设备管理·io设备
_李小白2 小时前
【Android FrameWork】第四十九天:SystemUI
android