framework自定义系统服务、实现回调

链接:

https://blog.csdn.net/weixin_44845266/article/details/121531578

前言:实现过程,App注册Callback,此时Callback注册进RemoteCallbackList中统一管理。

        例如在App传入x、y,在Framework实现加法运算返回运算结果 z 给App,那么就在ServiceManager.aidl中定义一个void sum(int x, int y)接口,在Callback.aidl中定义print(int z)接口,在实现接口的函数sum的函数体末尾加上执行print(int z),在sum函数中执行完 z=x+y 调用print函数,传入参数z,哪个App需要看到结果哪个App就重写print方法,即可得到回调的加和结果。下列例子中会做一个介绍。

        建议在AndroidStudio编写程序,然后改好包名粘贴进源码中参与编译,因为有些未知的import导包需要AndroidStudio识别。编译若报错为缺少哪些包,那就import导入哪些包再编译。

一、编写AIDL文件

路径:frameworks/base/core/java/android/app/IDmsServiceManager.aidl

外部调用接口:IDmsServiceManager.aidl

package android.app;
 
import android.app.IDmsCallback;
 
interface IDmsServiceManager {
  void registerCallback(IDmsCallback callback);
 
  void unregisterCallback(IDmsCallback callback);
 
  void sendMessage(int value);
}

路径:frameworks/base/core/java/android/app/IDmsCallback.aidl

callback:IDmsCallback.aidl

package android.app;
 
interface IDmsCallback{
    void print(int value);
}

目录:frameworks/base/Android.bp

        "core/java/android/app/IDmsCallBack.aidl",
        "core/java/android/app/IDmsServiceManager.aidl",

        如下所示,将这两行写入Android.bp文件中,在编译的时候会自动生成stub类

java_library {
    name: "framework",

    srcs: [
        // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
        "core/java/**/*.java",
        "graphics/java/**/*.java",
        "location/java/**/*.java",
        "lowpan/java/**/*.java",

        ..........

        "core/java/android/app/IWallpaperManager.aidl",
        "core/java/android/app/IWallpaperManagerCallback.aidl",
        "core/java/android/app/IDmsCallBack.aidl",
        "core/java/android/app/IDmsServiceManager.aidl",
        "core/java/android/app/admin/IDeviceAdminService.aidl",
        "core/java/android/app/admin/IDevicePolicyManager.aidl",
        ..........

二、编写Manager类对app层暴露接口

路径:frameworks/base/core/java/android/app/DmsManager.java

DMS管理类,应用层调用的接口:DmsManager.java

package android.app;

import android.content.Context;
import android.os.RemoteException;
import android.util.Log;


public class DmsManager {

  private final Context mContext;
  private final IDmsServiceManager mService;

  public DmsManager(Context context, IDmsServiceManager service) {
    mContext = context;
    mService = service;
  }

  public void register(IDmsallback callback) {
    try {
      mService.registerCallback(callback);
    } catch (RemoteException e) {
      Log.w(TAG, "remote exception happen");
      e.printStackTrace();
    }
  }

  public void unregister(IDmsCallback callback) {
    try {
      mService.unregisterCallback(callback);
    } catch (RemoteException e) {
      Log.w(TAG, "remote exception happen");
      e.printStackTrace();
    }
  }

  /**
   * Send data to DmsService.
   */
  public void sendMessage(int value) {
    try {
      mService.sendMessage(value);
    } catch (RemoteException e) {
      Log.w(TAG, "remote exception happen");
      e.printStackTrace();
    }
  }

}

三、接口实现

路径:frameworks/base/services/core/java/com/android/server/DmsService.java

实现IDmsServiceManager.aidl定义的接口:DmsService.java

package com.android.server

import android.app.IDmsServiceManager;
import android.app.IDmsCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import content.Context;
import android.util.Slog;

public class DmsService extends IDmsServiceManager.Stub{
    private final static String TAG = "DMS_SERVICE";

    private RemoteCallbackList<IDmsCallback> mCallbackList = new RemoteCallbackList<>();

    private final Context mContext;

    public DmsService (Context context){
        mContext = context;
    }

    @Override
    public void sendMessage(int value){
        Slog.i(TAG, "" + value);
        //注册在列表中的callback数量
        int count = mCallbackList.getRegisteredCallbackCount();
        if (count > 0) {
            final int size = mCallbackList.beginBroadcast();
            //遍历列表中的callback,对注册的每个callback执行print方法,客户端重写print方法后可以获得sendMessage执行结果
            for (int i = 0; i < size; i++) {
                IDmsCallback cb = mCallbackList.getBroadcastItem(i);
                try {
                    if (cb != null) {
                        cb.print(value);
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                    Log.d(TAG, "remote exception:" + e.getMessage());
                }
            }
        }
        mCallbackList.finishBroadcast();
    }

    
    @Override
    public void registerCallback(IDmsCallback callback){
        mCallbackList.register(callback);
    }


    @Override
    public void unregisterCallback(IDmsCallback callback){
        mCallbackList.unregister(callback);
    }

}

应用层注册的callback都会传进RemoteCallbackList列表中,调用回调接口时,可以轮询callback列表,对所有注册的callback进行回调。

接口都在该文件中实现,外部调用DmsManager方法是,调用的也是这里实现的方法。

四、注册系统服务

服务的接口已经实现,方法也对外界暴露,现在剩的就是注册成为系统服务和外界如何调用接口了。服务以系统服务进程的子线程的形式存在,Log打印在system_process进程中。

路径:frameworks/base/services/java/com/android/server/SystemServer.java

在该文化中注册成为系统服务,系统服务开启子线程

package com.android.server

private void startOtherServices() {
  // 部分代码省略...
  // start SystemEventService
    try {
        //Context.DMS_SERVICE是String类型,是服务名称
        ServiceManager.addService(Context.DMS_SERVICE,
        new DmsService(mSystemContext));
    } catch (Throwable e) {
        reportWtf("starting SystemEventService", e);
    }
  // 部分代码省略...
}

此时文件已经注册到系统服务中,系统开启时会自动开启DMS服务。

五、应用层调用接口

采用的是反射调用的方法,注册Manager文件,即DmsManager.java文件。注册后Manager会存入一个HasMap中,应用调用时通过getSystemService(Context.DMS_SERVICE);经过一系列方法找到对应的系统服务对象。

路径:frameworks/base/core/java/android/app/SystemServiceRegistry.java

package android.app;

static { 
  // 部分代码省略, 参考其他代码, 注册Manger
    registerService(Context.DMS_SERVICE, DmsManager.class,
        new CachedServiceFetcher<DmsManager>() {
    @Override
    public DmsManager createService(ContextImpl ctx) {
        // 获取服务
        IBinder b = ServiceManager.getService(Context.DMS_SERVICE);
        // 返回DmsManager对象供调用
        IDmsServiceManager service = IDmsServiceManager.Stub.asInterface(b);
        return new DmsManager(ctx.getOuterContext(), service);
    }});
}

六、还有部分权限问题,需要设置SELinux的权限

后面会告知service_contexts.te和service.te修改的位置

service_contexts.te

wifiscanner                u:object_r:wifiscanner_service:s0
wifi                       u:object_r:wifi_service:s0
window                     u:object_r:window_service:s0
# 部分代码省略...
# dms是系统服务名称,即Context.DMS_SERVICE
# dms_service 是新定义的参数,在下面的service.te文件中type定义为系统服务,这里需要百度一下,我不懂
dms                        u:object_r:dms_service:s0
*                          u:object_r:default_android_service:s0

service.te

# 加入刚刚定义好的 dms_service 类型, 表明它是系统服务,大家可以百度查查
type dms_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;

配置SELinux的sepolicy文件夹目录结构如下所示:

下面的两个文件按照上面的service_contexts.te和service.te代码段添加

        1、system/sepolicy/prebuilts/api/26.0/private/service_contexts.te

        2、system/sepolicy/prebuilts/api/26.0/public/service.te

        3、api目录下27.0和28.0目录同样的更改

        4、system/sepolicy/private/service.te

        5、system/sepolicy/public/service_contexts.te

        这些文件都更改一下肯定没有问题,但是也许可以只修改28.0目录的文件和4、5对应的文件,可以修改试一下,缺哪个SELinux权限就添加哪个SELinux权限。

七、编译

        在android目录下执行make_environment.sh脚本导入环境(或者执行

                                                                        source build/envsetup.sh和lunch 59)

        make update-api 更新api

        make -j8八线程编译

八、应用调用接口实现

1、make -j8 后的生成的中间文件classes.jar导入AndroidStudio中的lib目录下

        目录:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar

2、build.gradle文件配置

allprojects {
    repositories {
        google()
        jcenter()
    }
    //添加如下部分,以便调用方法的时候会优先使用导入的包classes.jar
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << '-Xbootclasspath/p:app/libs/classes.jar'
        }
    }
}

3、MainActivity.java

package com.example.dms;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.app.IDmsCallBack;
import android.content.Context;
import android.os.Bundle;
import android.app.DmsManager;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private Button send_btn;
    private Button register_btn;
    private Button unregister_btn;

    private String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //获取Context.DMS_SERVICE对应的系统服务,定义在classes.jar包中,编译的时候找不到,但可以编译通过
        DmsManager dms = (DmsManager) getSystemService(Context.DMS_SERVICE);

        requestPermissions(new String[]{Manifest.permission.UPDATE_DEVICE_STATS}, 0);

        camera_btn = findViewById(R.id.cameraPreview);
        register_btn = findViewById(R.id.registerCallback);
        unregister_btn = findViewById(R.id.unregisterCallback);

        send_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    dms.sendMessage(5);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });

        //注册下面实现的回调接口callBack 
        register_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                try {
                    dms.registerCallBack(callBack);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        //注销下面实现的回调接口callBack 
        unregister_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                try {
                    dms.unregisterCallBack(callBack);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //实现IDmsCallback回调接口定义的回调方法,可以再App看到打印的Log值
    private IDmsCallBack.Stub callBack = new IDmsCallBack.Stub() {
        @Override
        public void print(int value) throws RemoteException {
            Log.d(TAG, "" + value);

        }
    };
}

4、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.dms">
    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="DMS"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.DMS">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

layout部分自行编写,就不贴了

此时build完成后,安装App实现调用

学习链接:

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>