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 了:

参考资料

相关推荐
sun0077005 小时前
android ndk编译valgrind
android
AI视觉网奇7 小时前
android studio 断点无效
android·ide·android studio
jiaxi的天空7 小时前
android studio gradle 访问不了
android·ide·android studio
No Silver Bullet8 小时前
android组包时会把从maven私服获取的包下载到本地吗
android
catchadmin8 小时前
PHP serialize 序列化完全指南
android·开发语言·php
tangweiguo030519879 小时前
Kable使用指南:Android BLE开发的现代化解决方案
android·kotlin
00后程序员张12 小时前
iOS App 混淆与资源保护:iOS配置文件加密、ipa文件安全、代码与多媒体资源防护全流程指南
android·安全·ios·小程序·uni-app·cocoa·iphone
柳岸风13 小时前
Android Studio Meerkat | 2024.3.1 Gradle Tasks不展示
android·ide·android studio
编程乐学13 小时前
安卓原创--基于 Android 开发的菜单管理系统
android
whatever who cares15 小时前
android中ViewModel 和 onSaveInstanceState 的最佳使用方法
android