当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Android 添加系统服务的方法详解

    栏目:Linux/apache问题 时间:2020-02-06 08:25

    一、前言

    系统服务是Android中非常重要的一部分, 像ActivityManagerService, PackageManagerService, WindowManagerService, 这些系统服务都是Framework层的关键服务, 本篇文章主要讲一下如何基于Android源码添加一个系统服务的完整流程, 除了添加基本系统服务, 其中还包含添加JNI部分代码和App通过AIDL调用的演示Demo, 调用包含App调用服务端, 也包含服务端回调App, 也就是完成一个简单的双向通信.

    注: 测试代码基于Android 7.1.1, 其他Android版本都是大同小异.

    二、编写AIDL文件

    添加服务首先是编写AIDL文件, AIDL文件路径如下:

    frameworks/base/core/java/com/example/utils/

    1.ISystemEvent.aidl 内容如下:

    package com.example.utils;
    
    import com.example.utils.IEventCallback;
    
    interface ISystemEvent {
      void registerCallback(IEventCallback callback);
    
      void unregisterCallback(IEventCallback callback);
    
      void sendEvent(int type, String value);
    }
    
    

    2.IEventCallback.aidl 内容如下

    package com.example.utils;
    
    interface IEventCallback
    {
      oneway void onSystemEvent(int type, String value);
    }
    
    

    AIDL文件编写, 教程很多, 我这里就不详细说明了, 需要注意的是, 由于我们要实现回调功能, 所以必须写一个回调接口 IEventCallback, 另外AIDL文件中 oneway 关键字表明调用此函数不会阻塞当前线程, 调用端调用此函数会立即返回, 接收端收到函数调用是在Binder线程池中的某个线程中. 可以根据实际项目需求选择是否需要加 oneway 关键字.

    AIDL只支持传输基本java类型数据, 要想传递自定义类, 类需要实现 Parcelable 接口, 另外, 如果传递基本类型数组, 需要指定 in out 关键字, 比如 void test(in byte[] input, out byte[] output) , 用 in 还是 out, 只需要记住: 数组如果作为参数, 通过调用端传给被调端, 则使用 in, 如果数组只是用来接受数据, 实际数据是由被调用端来填充的, 则使用 out, 这里之所以没有说服务端和客户端, 是因为 in out 关键字用哪个和是服务端还是客户端没有联系, 远程调用和被调用更适合描述.

    文件写完后, 添加到编译的 Android.mk 中 LOCAL_SRC_FILES 后面:

    3.frameworks/base/Android.mk

    LOCAL_SRC_FILES += \
      core/java/android/view/IWindow.aidl \
      core/java/android/view/IWindowFocusObserver.aidl \
      core/java/android/view/IWindowId.aidl \
      部分代码省略 ...
      core/java/com/example/utils/ISystemEvent.aidl \
      core/java/com/example/utils/IEventCallback.aidl \
      部分代码省略 ...
    

    编译代码, 编译前需执行 make update-api, 更新接口, 然后编译代码,确保AIDL编写没有错误, 编译后会生成对应java文件, 服务端要实现对应接口.

    三、编写Manager类

    我们可以看到, Android API 中有很多Manager类, 这些类一般都是某个系统服务的客户端代理类, 其实我们不写Manager类, 只通过AIDL文件自动生成的类, 也可以完成功能, 但封装一下AIDL接口使用起来更方便, 我们测试用的Manager类为 SystemEventManager, 代码如下:

    frameworks/base/core/java/com/example/utils/SystemEventManager.java

    package com.example.utils;
    
    import android.content.Context;
    import android.os.RemoteException;
    import android.util.Log;
    
    import com.example.example.ISystemEvent;
    import com.example.IEventCallback;
    
    public class SystemEventManager {
    
      private static final String TAG = SystemEventManager.class.getSimpleName();
      // 系统服务注册时使用的名字, 确保和已有的服务名字不冲突
      public static final String SERVICE = "test_systemevent";
    
      private final Context mContext;
      private final ISystemEvent mService;
    
      public SystemEventManager(Context context, ISystemEvent service) {
        mContext = context;
        mService = service;
        Log.d(TAG, "SystemEventManager init");
      }
    
      public void register(IEventCallback callback) {
        try {
          mService.registerCallback(callback);
        } catch (RemoteException e) {
          Log.w(TAG, "remote exception happen");
          e.printStackTrace();
        }
      }
    
      public void unregister(IEventCallback callback) {
        try {
          mService.unregisterCallback(callback);
        } catch (RemoteException e) {
          Log.w(TAG, "remote exception happen");
          e.printStackTrace();
        }
      }
    
      /**
       * Send event to SystemEventService.
       */
      public void sendEvent(int type, String value) {
        try {
          mService.sendEvent(type, value);
        } catch (RemoteException e) {
          Log.w(TAG, "remote exception happen");
          e.printStackTrace();
        }
      }
    }