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

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

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

    代码很简单, 就封装了下AIDL接口, 定义了系统服务注册时用的名字.

    public SystemEventManager(Context context, ISystemEvent service)
    

    构造函数中的 ISystemEvent 参数在后面注册Manager时候会通过Binder相关接口获取.

    编译代码, 确保没有错误, 下面编写系统服务.

    四、 编写系统服务

    路径以及代码如下:
    frameworks/base/services/core/java/com/android/server/example/SystemEventService.java

    package com.android.server.example;
    
    import android.content.Context;
    import android.os.Binder;
    import android.os.RemoteCallbackList;
    import android.os.RemoteException;
    import android.os.ServiceManager;
    import android.util.Log;
    
    import com.example.utils.ISystemEvent;
    import com.example.utils.IEventCallback;
    
    public class SystemEventService extends ISystemEvent.Stub {
    
      private static final String TAG = SystemEventService.class.getSimpleName();
      private RemoteCallbackList<IEventCallback> mCallbackList = new RemoteCallbackList<>();
    
      private Context mContext;
    
      public SystemEventService(Context context) {
        mContext = context;
        Log.d(TAG, "SystemEventService init");
      }
    
      @Override
      public void registerCallback(IEventCallback callback) {
        boolean result = mCallbackList.register(callback);
        Log.d(TAG, "register pid:" + Binder.getCallingPid()
            + " uid:" + Binder.getCallingUid() + " result:" + result);
    
      }
    
      @Override
      public void unregisterCallback(IEventCallback callback) {
        boolean result = mCallbackList.unregister(callback);
        Log.d(TAG, "unregister pid:" + Binder.getCallingPid()
            + " uid:" + Binder.getCallingUid() + " result:" + result);
    
      }
    
      @Override
      public void sendEvent(int type, String value) {
        sendEventToRemote(type, value + " remote");
      }
    
      public void sendEventToRemote(int type, String value) {
        int count = mCallbackList.getRegisteredCallbackCount();
        Log.d(TAG, "remote callback count:" + count);
        if (count > 0) {
          final int size = mCallbackList.beginBroadcast();
          for (int i = 0; i < size; i++) {
            IEventCallback cb = mCallbackList.getBroadcastItem(i);
            try {
              if (cb != null) {
                cb.onSystemEvent(type, value);
              }
            } catch (RemoteException e) {
              e.printStackTrace();
              Log.d(TAG, "remote exception:" + e.getMessage());
            }
          }
          mCallbackList.finishBroadcast();
        }
      }
    }
    
    

    服务端继承自 ISystemEvent.Stub, 实现对应的三个方法即可, 需要注意的是, 由于有回调功能, 所以要把注册的 IEventCallback 加到链表里面, 这里使用了 RemoteCallbackList, 之所以不能使用普通的 List 或者 Map, 原因是, 跨进程调用, App调用 registerCallback 和 unregisterCallback 时, 即便每次传递的都是同一个 IEventCallback 对象, 但到服务端, 经过跨进程处理后, 就会生成不同的对象, 所以不能通过直接比较是否是同一个对象来判断是不是同一个客户端对象, Android中专门用来处理跨进程调用回调的类就是 RemoteCallbackList, RemoteCallbackList 还能自动处理App端异常死亡情况, 这种情况会自动移除已经注册的回调.

    RemoteCallbackList 使用非常简单, 注册和移除分别调用 register() 和 unregister() 即可, 遍历所有Callback 稍微麻烦一点, 代码参考上面的 sendEventToRemote() 方法.