Android Java 系统服务框架与第三方 App 使用自定义 Java 系统服务

Android Java 系统服务框架

我们在 Android 开发过程中经常会用到各种各样的系统管理服务,如进行窗口相关的操作会用到窗口管理服务 WindowManager,进行电源相关的操作会用到电源管理服务 PowerManager,还有很多其他的系统管理服务,如通知管理服务 NotifacationManager、振动管理服务 Vibrator、电池管理服务 BatteryManager......

这些 Manager 提供了很多对系统层的控制接口。对于 App 开发者,只需要了解这些接口的使用方式就可以方便的进行系统控制,获得系统各个服务的信息,而不需要了解这些接口的具体实现方式。而对于 Framework 开发者,则需要了解这些 Manager 服务的常用实现模式,维护这些 Manager 的接口,扩展这些接口,或者实现新的Manager。

我们从一个简单的系统服务 Vibrator 服务来看一下一个系统服务是怎样建立的。

Vibrator服务提供的控制手机振动的接口,应用可以调用 Vibrator 的接口来让手机产生振动,达到提醒用户的目的。 从源码(frameworks/base/core/java/android/os/Vibrator.java)中可以看到 Vibrator 是一个抽象类,常用的接口如下:

java 复制代码
    /*
    * 是否有振动功能
    */
    public abstract boolean hasVibrator();

    /*
     * 持续振动,但是已经 Deprecated 了
     */
    @Deprecated
    @RequiresPermission(android.Manifest.permission.VIBRATE)
    public void vibrate(long milliseconds) {
        vibrate(milliseconds, null);
    }

    /*
     * 按节奏重复振动,但是已经 Deprecated 了
     */
    @Deprecated
    @RequiresPermission(android.Manifest.permission.VIBRATE)
    public void vibrate(long[] pattern, int repeat) {
        vibrate(pattern, repeat, null);
    }

    /*
     * 用于代替上面两个接口
     */
    @RequiresPermission(android.Manifest.permission.VIBRATE)
    public void vibrate(VibrationEffect vibe) {
        vibrate(vibe, null);
    }

应用中使用振动服务的方法也很简单,如让手机持续振动500毫秒:

java 复制代码
Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);

接着我们看下 Vibrator 的获取过程:

getSystemService 方法定义在 frameworks/base/core/java/android/app/ContextImpl.java 中:

java 复制代码
@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

SystemServiceRegistry.getSystemService 定义在 frameworks/base/core/java/android/app/SystemServiceRegistry.java 中:

java 复制代码
public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

上述代码使用了 SYSTEM_SERVICE_FETCHERS,SYSTEM_SERVICE_FETCHERS 是一个 Map 类型:

java 复制代码
private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
        new ArrayMap<String, ServiceFetcher<?>>();

其数据通过 registerService 方法插入:

java 复制代码
private static <T> void registerService(String serviceName, Class<T> serviceClass,
        ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}

在 SystemServiceRegistry 的静态块中调用了 registerService 插入 Vibrator 对象:

java 复制代码
static {

    registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
        new CachedServiceFetcher<Vibrator>() {
            @Override
            public Vibrator createService(ContextImpl ctx) {
                    return new SystemVibrator(ctx);
        }});

}

这里传入了一个匿名对象,内部方法返回了一个 new 出来的 SystemVibrator,其具体实现如下:

java 复制代码
// frameworks/base/core/java/android/os/SystemVibrator.java
// 客户端代理类的马甲
public class SystemVibrator extends Vibrator {
    private static final String TAG = "Vibrator";

    private final IVibratorService mService;
    private final Binder mToken = new Binder();

    @UnsupportedAppUsage
    public SystemVibrator() {
        mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));
    }

    @UnsupportedAppUsage
    public SystemVibrator(Context context) {
        super(context);
        mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));
    }

    @Override
    public boolean hasVibrator() {
        if (mService == null) {
            Log.w(TAG, "Failed to vibrate; no vibrator service.");
            return false;
        }
        try {
            return mService.hasVibrator();
        } catch (RemoteException e) {
        }
        return false;
    }

    @Override
    public boolean hasAmplitudeControl() {
        if (mService == null) {
            Log.w(TAG, "Failed to check amplitude control; no vibrator service.");
            return false;
        }
        try {
            return mService.hasAmplitudeControl();
        } catch (RemoteException e) {
        }
        return false;
    }

    @Override
    public void vibrate(int uid, String opPkg, VibrationEffect effect,
            String reason, AudioAttributes attributes) {
        if (mService == null) {
            Log.w(TAG, "Failed to vibrate; no vibrator service.");
            return;
        }
        try {
            mService.vibrate(uid, opPkg, effect, attributes, reason, mToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to vibrate.", e);
        }
    }

    @Override
    public void cancel() {
        if (mService == null) {
            return;
        }
        try {
            mService.cancelVibrate(mToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to cancel vibration.", e);
        }
    }
}

在构造函数中有我们熟悉的 AIDL 生成代码,通过 IVibratorService.Stub.asInterface 构建了一个 IVibratorService 代理类。SystemVibrator 通过 IVibratorService 代理类实现了 Vibrator 抽象类的对外接口。

IVibratorService 通过 AIDL 生成:

java 复制代码
// frameworks/base/core/java/android/os/IVibratorService.aidl
package android.os;

import android.media.AudioAttributes;
import android.os.VibrationEffect;

/** {@hide} */
interface IVibratorService
{
    boolean hasVibrator();
    boolean hasAmplitudeControl();
    void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes,
            String reason, IBinder token);
    void cancelVibrate(IBinder token);
}

除了 AIDL 生成的代理端,还需要对应的服务端类,这个类是 VibratorService,需要自己实现:

java 复制代码
// frameworks/base/services/core/java/com/android/server/VibratorService.java

public class VibratorService extends IVibratorService.Stub {
    //......

}

振动器的实际操作都是通过 VibratorService 中的 native 函数实现,在 native 层中再调用到 hal 层,hal 层操作驱动,驱动操作实际硬件来完成。

接着我们再来看看,该系统服务是如何启动的:

java 复制代码
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
    // ......
    VibratorService vibrator = null;
    // ......
    traceBeginAndSlog("StartVibratorService");
    vibrator = new VibratorService(context);
    ServiceManager.addService("vibrator", vibrator);
    traceEnd();
}

从上面的分析,我们可以总结出 Vibrator 服务的整个实现流程:

服务端

  1. 实现一个 AIDL 接口文件 IVibratorService(frameworks/base/core/java/android/os/IVibratorService.aidl),定义系统服务接口

  2. 定义 Binder 服务端实现类 VibratorService,实现 IVibratorService 定义的接口 frameworks/base/services/java/com/android/server/VibratorService.java

    java 复制代码
    public class VibratorService extends IVibratorService.Stub {
     //......
    }
  3. VibratorService 开机启动 frameworks/base/services/java/com/android/server/SystemServer.java

客户端

  1. frameworks/base/core/java/android/content/Context.java 中添加服务注册名称, 添加该服务名称, 用于快捷注册和快捷引用
  2. 实现一个抽象类 Vibrator (frameworks/base/core/java/android/os/Vibrator.java),定义了应用中可以访问的一些抽象方法
  3. 定义 SystemVibrator 类 (frameworks/base/core/java/android/os/SystemVibrator.java),继承 Vibrator,实现抽象方法,实际就是 Vibrator Binder 服务端代理类马甲,所有的接口功能都是通过 Binder 服务端代理类实现。
  4. 在 SystemServiceRegistry 的静态块中调用了 registerService 插入 SystemVibrator 对象

第三方 App 使用自定义 Java 系统服务

添加 Java 系统服务 中我们添加了一个 Java 系统服务,不过这个服务并没有按照 Android Java 系统服务框架 的要求编写,导致我们只能在系统 App 中使用我们自定义的 Java 系统服务,接下来我们根据上文的分析来改造它,使得我们能在第三方 App 中使用我们自定义的 Java 系统服务。

服务端不用改动,主要是客户端:

Context.java 中添加服务注册名称, 添加该服务名称, 用于快捷注册和快捷引用:

java 复制代码
    // frameworks/base/core/java/android/content/Context.java
   public static final String JAVA_HELLO_SERVICE = "java_hello_service";

    /** @hide */
    @StringDef(suffix = { "_SERVICE" }, value = {
            JAVA_HELLO_SERVICE,
            POWER_SERVICE,
            WINDOW_SERVICE,
            //......
    }    

实现一个抽象类 JavaHello:

java 复制代码
// frameworks/base/core/java/com/yuandaima/JavaHello.java
package com.yuandaima;

public abstract class JavaHello {
    abstract void sayhello();
	abstract int sayhello_to(String name);
}

定义 SystemJavaHello 类 ,继承 JavaHello,实现抽象方法:

java 复制代码
package com.yuandaima;

import android.os.ServiceManager;
import android.os.RemoteException;

public class SystemJavaHello extends JavaHello {

    private final IJavaHelloService mService;

    public SystemJavaHello() {
        mService = IJavaHelloService.Stub.asInterface(ServiceManager.getService("JavaHelloService"));
    }

    public void sayhello() {
        if(mService != null) {
            try {
                mService.sayhello();
            } catch (RemoteException e) {
            }
        }
    }

	public int sayhello_to(String name) {
        if(mService != null) {
            try {
                return mService.sayhello_to(name);
            } catch (RemoteException e) {
            }
        } 
        return 0;
    }
}

接着在 frameworks/base/core/java/android/app/SystemServiceRegistry.java 的静态块中调用了 registerService 插入 SystemJavaHello 对象:

java 复制代码
import com.yuandaima.SystemJavaHello;
import com.yuandaima.JavaHello;

static {
        registerService(Context.JAVA_HELLO_SERVICE, JavaHello.class,
            new CachedServiceFetcher<JavaHello>() {
        @Override
        public Vibrator createService(ContextImpl ctx) {
            return new SystemJavaHello();
        }});
}

在 Android 10 中,针对非 SDK 接口进行了限制,默认是 blacklist 的,为了让我们的 App 能使用我们自定义的 Java 服务,需要在 frameworks/base/config/hiddenapi-greylist-packages.txt 中最后一行增加:

bash 复制代码
com.yuandaima

接着编译系统启动模拟器:

bash 复制代码
source build/envsetup.sh
lunch  rice14-eng
make update-api
make -j32
emulator

然后编译 App 使用的 Jar 包:

bash 复制代码
source build/envsetup.sh
lunch rice14-eng
# Android10 及以前
make framework
# Android11 及以后
#make framework-minus-apex

编译完成后,我们在 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates 目录下找到 classes.jar 文件,为方便识别,我们将该文件拷贝到其他地方,并将文件名修改为 framework.jar

使用 Android Studio(推荐版本 3.6.3) 创建一个 Empty Activity 空项目。接着把之前准备好的 framework.jar 拷贝到项目的 app/framework 文件夹中。

接着修改项目根目录下的 build.gradle,添加如下内容:

groovy 复制代码
allprojects {

    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            //相对位置,根据存放的位置修改路径
            options.compilerArgs.add('-Xbootclasspath/p:app/framework/framework.jar')
        }
    }

    repositories {
        google()
        jcenter()
        
    }
}

接着修改 app/build.gradle:

groovy 复制代码
dependencies {
    compileOnly files('framework/framework.jar')
    //.......
}

最后在 MainActivity 中加入使用自定义服务的代码:

java 复制代码
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        JavaHello javaHello = (JavaHello) getSystemService(Context.JAVA_HELLO_SERVICE);
        javaHello.sayhello_to("test");
    }
}

接着添加 selinux 配置:

同时修改 system/sepolicy/private 和 system/sepolicy/prebuilts/api/29.0/private 目录下的:

untrusted_app.te

arduino 复制代码
allow untrusted_app JavaHelloServiceType:service_manager find;

接着运行启动 App,就可以在看到我们调用成功的 Log 了:

参考资料

相关推荐
想取一个与众不同的名字好难1 小时前
android studio导入OpenCv并改造成.kts版本
android·ide·android studio
Jewel1052 小时前
Flutter代码混淆
android·flutter·ios
Yawesh_best3 小时前
MySQL(5)【数据类型 —— 字符串类型】
android·mysql·adb
曾经的三心草5 小时前
Mysql之约束与事件
android·数据库·mysql·事件·约束
guoruijun_2012_49 小时前
fastadmin多个表crud连表操作步骤
android·java·开发语言
Winston Wood9 小时前
一文了解Android中的AudioFlinger
android·音频
B.-11 小时前
Flutter 应用在真机上调试的流程
android·flutter·ios·xcode·android-studio
有趣的杰克11 小时前
Flutter【04】高性能表单架构设计
android·flutter·dart
大耳猫16 小时前
主动测量View的宽高
android·ui
帅次19 小时前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat