mirror of
https://github.com/feicong/rom-course.git
synced 2025-08-29 02:35:20 +00:00
第6章 6.4完成
This commit is contained in:
parent
ea8f82ff7e
commit
4dd4af3b0a
@ -408,21 +408,376 @@ mik.nativedem: mikrom ClassLinker::RegisterNative java.lang.String cn.mik.native
|
||||
|
||||
## 6.4 自定义系统服务
|
||||
|
||||
自定义系统服务是指在操作系统中创建自己的服务,以便在需要时可以使用它。系统服务可以在启动时自动运行且没有UI界面,并在后台执行某些特定任务或提供某些功能。由于系统服务有着system身份的权限,所以自定义系统服务可以用于各种用途。例如如下:
|
||||
|
||||
1. 系统监控与管理:通过定期收集和分析系统数据,自动化报警和管理,保证系统稳定性和安全性;
|
||||
2. 自动化部署和升级:通过编写脚本和程序实现自动化部署和升级软件,简化人工干预过程;
|
||||
3. 数据备份与恢复:通过编写脚本和程序实现数据备份和恢复,保证数据安全性和连续性;
|
||||
4. 后台任务处理:例如定时清理缓存、定时更新索引等任务,减轻人工干预压力,提高系统效率。
|
||||
|
||||
在第三章简单介绍过系统服务的启动,添加一个自定义的系统服务可以参考AOSP源码中的添加方式来逐步完成。接下来参考源码来添加一个最简单的系统服务`MIK_SERVICE`。
|
||||
|
||||
首先在文件`frameworks/base/core/java/android/content/Context.java`看到了定义了各种系统服务的名称,在这里参考`POWER_SERVICE`服务的添加,在这个服务的下面添加自定义的服务,同时找到该文件中,其他对`POWER_SERVICE`进行处理的地方,将自定义的服务做同样的处理,相关代码如下
|
||||
|
||||
```java
|
||||
public abstract class Context {
|
||||
@StringDef(suffix = { "_SERVICE" }, value = {
|
||||
POWER_SERVICE,
|
||||
...
|
||||
MIKROM_SERVICE,
|
||||
})
|
||||
...
|
||||
public static final String POWER_SERVICE = "power";
|
||||
public static final String MIKROM_SERVICE = "mikrom";
|
||||
}
|
||||
```
|
||||
|
||||
接着搜索`POWER_SERVICE`找到该服务注册的地方,找到了文件`frameworks/base/core/java/android/app/SystemServiceRegistry.java`中进行了注册,所以在注册该服务的下方,模仿源码添加对自定义服务的注册。
|
||||
|
||||
```java
|
||||
public final class SystemServiceRegistry {
|
||||
...
|
||||
static {
|
||||
...
|
||||
registerService(Context.POWER_SERVICE, PowerManager.class,
|
||||
new CachedServiceFetcher<PowerManager>() {
|
||||
@Override
|
||||
public PowerManager createService(ContextImpl ctx) throws ServiceNotFoundException {
|
||||
IBinder powerBinder = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);
|
||||
IPowerManager powerService = IPowerManager.Stub.asInterface(powerBinder);
|
||||
IBinder thermalBinder = ServiceManager.getServiceOrThrow(Context.THERMAL_SERVICE);
|
||||
IThermalService thermalService = IThermalService.Stub.asInterface(thermalBinder);
|
||||
return new PowerManager(ctx.getOuterContext(), powerService, thermalService,
|
||||
ctx.mMainThread.getHandler());
|
||||
}});
|
||||
|
||||
registerService(Context.MIKROM_SERVICE, MikRomManager.class,
|
||||
new CachedServiceFetcher<MikRomManager>() {
|
||||
@Override
|
||||
public MikRomManager createService(ContextImpl ctx) throws ServiceNotFoundException {
|
||||
IBinder mikromBinder = ServiceManager.getServiceOrThrow(Context.MIKROM_SERVICE);
|
||||
IMikRomManager mikromService = IMikRomManager.Stub.asInterface(mikromBinder);
|
||||
return new MikRomManager(ctx.getOuterContext(), mikromService, ctx.mMainThread.getHandler());
|
||||
}});
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
`PowerManager`的功能中用到了`THERMAL_SERVICE`系统服务,所以这里不必完全照搬,省略掉这个参数即可。接下来发现注册时用到的`IMikRomManager`、`MikRomManager`并不存在,所以继续参考`PowerManager`的实现,先寻找`IPowerManager`在哪里定义的,通过搜索,发现该接口在文件`frameworks/base/core/java/android/os/IPowerManager.aidl`中。在同目录下新建文件`IMikRomManager.aidl`并添加简单的接口内容如下。
|
||||
|
||||
```java
|
||||
package android.os;
|
||||
|
||||
interface IMikRomManager
|
||||
{
|
||||
String hello();
|
||||
}
|
||||
```
|
||||
|
||||
AIDL(Android 接口定义语言)是一种 Android 平台上的 IPC 机制,用于不同应用程序组件之间进行进程通信。要使用 AIDL 实现进程间通信,需要定义一个接口文件并实现它,在服务端和客户端之间传递 Parcelable 类型的数据。
|
||||
|
||||
在 Android 中使用 AIDL 首先需要创建一个 .aidl 文件来定义接口。接下来,将 .aidl 文件编译成 Java 接口,并在服务端和客户端中分别实现该接口。最后,在服务端通过 bindService() 方法绑定服务并向客户端返回 IBinder 对象。使用 AIDL 可以轻松地实现跨进程通信,但需要考虑线程安全性和数据完整性等问题。
|
||||
|
||||
添加完毕后还需要找到在哪里将这个文件添加到编译中的,搜索`IPowerManager.aidl`后,找到文件`frameworks/base/core/java/Android.bp`中进行处理的。所以跟着添加上刚刚定义的aidl文件。修改如下。
|
||||
|
||||
```
|
||||
filegroup {
|
||||
name: "libpowermanager_aidl",
|
||||
srcs: [
|
||||
...
|
||||
"android/os/IPowerManager.aidl",
|
||||
"android/os/IMikRomManager.aidl",
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
然后继续寻找`IPowerManager.aidl`在哪里进行实现的,搜索`IPowerManager.Stub`,找到文件`frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java`实现的具体的逻辑。该服务的路径是在power目录下,并不适合存放自定义的服务,所以选择在更上级目录创建一个对应的新文件`frameworks/base/services/core/java/com/android/server/MikRomManagerService.java`,代码如下。
|
||||
|
||||
```java
|
||||
public class MikRomManagerService extends IMikRomManager.Stub {
|
||||
private Context mContext;
|
||||
private String TAG="MikRomManagerService";
|
||||
public MikRomManagerService(Context context){
|
||||
mContext=context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String hello(){
|
||||
return "hello mikrom service";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
接着找到`PowerManager`在文件` frameworks/base/core/java/android/os/PowerManager.java`中实现,所以在这个目录中创建文件`MikRomManager.java`,代码实现如下。
|
||||
|
||||
```java
|
||||
package android.os;
|
||||
|
||||
@SystemService(Context.MIKROM_SERVICE)
|
||||
public final class MikRomManager {
|
||||
private static final String TAG = "MikRomManager";
|
||||
final Context mContext;
|
||||
@UnsupportedAppUsage
|
||||
final IMikRomManager mService;
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
|
||||
final Handler mHandler;
|
||||
public MikRomManager(Context context, IMikRomManager service,Handler handler) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
public String hello(){
|
||||
return mService.hello();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
到这里注册一个自定义的系统服务基本完成了,最后是启动这个自定义的服务,而启动的流程在第三章中有详细的介绍,在文件`frameworks/base/services/java/com/android/server/SystemServer.java`中启动,这里选择系统准备就绪后的时机再拉起这个服务,参考其他任意服务启动的方式即可。
|
||||
|
||||
```java
|
||||
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
|
||||
|
||||
...
|
||||
t.traceBegin("StartNetworkStatsService");
|
||||
try {
|
||||
networkStats = NetworkStatsService.create(context, networkManagement);
|
||||
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting NetworkStats Service", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
|
||||
|
||||
t.traceBegin("StartMikRomManagerService");
|
||||
try {
|
||||
MikRomManagerService mikromService = new MikRomManagerService(context);
|
||||
ServiceManager.addService(Context.MIKROM_SERVICE,mikromService);
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting MikRom Service", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
到这里基本准备就绪了,可以开始尝试编译,由于添加了aidl文件,所以需要先调用`make update-api`进行编译,编译过程如下,最后出现编译报错。
|
||||
|
||||
```
|
||||
source ./build/envsetup.sh
|
||||
|
||||
lunch aosp_blueline-userdebug
|
||||
|
||||
make update-api -j8
|
||||
|
||||
// 出现下面的错误
|
||||
frameworks/base/core/java/android/os/MikRomManager.java:10: error: Method parameter type `android.content.Context` violates package layering: nothin
|
||||
g in `package android.os` should depend on `package android.content` [PackageLayering]
|
||||
frameworks/base/core/java/android/os/MikRomManager.java:16: error: Managers must always be obtained from Context; no direct constructors [ManagerCon
|
||||
structor]
|
||||
frameworks/base/core/java/android/os/MikRomManager.java:16: error: Missing nullability on parameter `context` in method `MikRomManager` [MissingNull
|
||||
ability]
|
||||
frameworks/base/core/java/android/os/MikRomManager.java:16: error: Missing nullability on parameter `service` in method `MikRomManager` [MissingNull
|
||||
ability]
|
||||
```
|
||||
|
||||
这是由于Android 11 以后谷歌强制开启lint检查来提高应用程序的质量和稳定性。Lint检查是Android Studio中的一个静态分析工具,用于检测代码中可能存在的潜在问题和错误。它可以帮助开发人员找到并修复代码中的bug、性能问题、安全漏洞等。可以设置让其忽略掉对这个`android.os`目录的检查,修改文件`framewoks/base/Android.bp`文件如下。
|
||||
|
||||
```
|
||||
metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
|
||||
...
|
||||
"--api-lint-ignore-prefix android.os."
|
||||
```
|
||||
|
||||
提示需要将Managers必须是单例模式,并且String是允许为null值的,参数或返回值需要携带`@Nullable`注解,调用service函数时,需要捕获异常。针对以上的提示对`MikRomManager`进行调整如下。
|
||||
|
||||
```java
|
||||
package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
import android.annotation.SystemService;
|
||||
import android.os.IMikRomManager;
|
||||
|
||||
@SystemService(Context.MIKROM_SERVICE)
|
||||
public final class MikRomManager {
|
||||
private static final String TAG = "MikRomManager";
|
||||
IMikRomManager mService;
|
||||
public MikRomManager(IMikRomManager service) {
|
||||
mService = service;
|
||||
}
|
||||
private static MikRomManager sInstance;
|
||||
/**
|
||||
*@hide
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage
|
||||
public static MikRomManager getInstance() {
|
||||
synchronized (MikRomManager.class) {
|
||||
if (sInstance == null) {
|
||||
try {
|
||||
IBinder mikromBinder = ServiceManager.getServiceOrThrow(Context.MIKROM_SERVICE);
|
||||
IMikRomManager mikromService = IMikRomManager.Stub.asInterface(mikromBinder);
|
||||
sInstance= new MikRomManager(mikromService);
|
||||
} catch (ServiceManager.ServiceNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
}
|
||||
@Nullable
|
||||
public String hello(){
|
||||
try{
|
||||
return mService.hello();
|
||||
}catch (RemoteException ex){
|
||||
throw ex.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
除此之外,在注册该服务的地方也要对应的调整初始化的方式。调整如下
|
||||
|
||||
```java
|
||||
public final class SystemServiceRegistry {
|
||||
...
|
||||
static {
|
||||
...
|
||||
registerService(Context.MIKROM_SERVICE, MikRomManager.class,
|
||||
new CachedServiceFetcher<MikRomManager>() {
|
||||
@Override
|
||||
public MikRomManager createService(ContextImpl ctx) throws ServiceNotFoundException {
|
||||
return MikRomManager.getInstance();
|
||||
}});
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
经过修改后,再重新编译就能正常编译完成了,最后还需要对selinux进行修改,对新增的服务开放权限。找到文件`system/sepolicy/public/service.te`,参考其他的服务定义,在最后添加一条类型定义如下。
|
||||
|
||||
```
|
||||
type mikrom_service, system_api_service, system_server_service, service_manager_type;
|
||||
```
|
||||
|
||||
然后找到文件`system/sepolicy/private/service_contexts`,在最后给我们`Context`中定义的`mikrom`服务设置使用刚刚定义的`mikrom_service`类型的权限,修改如下。
|
||||
|
||||
```
|
||||
mikrom u:object_r:mikrom_service:s0
|
||||
```
|
||||
|
||||
为自定义的系统服务添加了selinux权限后,还需要给应用开启权限访问这个系统服务,找到`system/sepolicy/public/untrusted_app.te`文件,添加如下策略开放让其能查找该系统服务。
|
||||
|
||||
```
|
||||
allow untrusted_app mikrom_service:service_manager find;
|
||||
allow untrusted_app_27 mikrom_service:service_manager find;
|
||||
allow untrusted_app_25 mikrom_service:service_manager find;
|
||||
```
|
||||
|
||||
这时如果直接编译会出现下面的错误。
|
||||
|
||||
```
|
||||
FAILED: /home/king/android_src/mikrom_out/target/product/blueline/obj/FAKE/sepolicy_freeze_test_intermediates/sepolicy_freeze_test
|
||||
/bin/bash -c "(diff -rq -x bug_map system/sepolicy/prebuilts/api/31.0/public system/sepolicy/public ) && (diff -rq -x bug_map system/sepolicy/prebui
|
||||
lts/api/31.0/private system/sepolicy/private ) && (touch /home/king/android_src/mikrom_out/target/product/blueline/obj/FAKE/sepolicy_freeze_test_int
|
||||
ermediates/sepolicy_freeze_test )"
|
||||
```
|
||||
|
||||
在前文介绍selinux时有说到系统会使用 prebuilts 中的策略进行对比,这是因为 prebuilts 中包含了在 Android 设备上预置的 sepolicy 策略和规则。所以当改动策略时,要将prebuilts 下对应的文件做出相同的修改。因为对应要调整`system/sepolicy/prebuilts/api/31.0/public/service.te`和`system/sepolicy/prebuilts/api/31.0/private/service_contexts`进行和上面相同的调整。这里需要注意的是`untrusted_app.te`文件只需要修改`prebuilts/api/31.0`的即可,而`service.te`和`service_contexts`,需要将`prebuilts/api/`目录下所有版本都添加定义,否则会出现如下错误。
|
||||
|
||||
```
|
||||
SELinux: The following public types were found added to the policy without an entry into the compatibility mapping file(s) found in private/compat/V
|
||||
.v/V.v[.ignore].cil, where V.v is the latest API level.
|
||||
```
|
||||
|
||||
到这里selinux策略就基本修改完毕,成功编译后,刷入手机,检查服务是否成功开启。
|
||||
|
||||
```
|
||||
adb shell
|
||||
|
||||
service list|grep mikrom
|
||||
|
||||
// 成功查询到自定义的系统服务
|
||||
120 mikrom: [android.os.IMikRomManager]
|
||||
```
|
||||
|
||||
最后开发一个测试的app对这个系统服务调用hello函数。创建一个Android项目,在java目录下创建一个package路径`android.os`,然后再这个package下创建一个文件`IMikRomManager.aidl`,内容和前文添加系统服务时一至,内容如下。
|
||||
|
||||
```java
|
||||
package android.os;
|
||||
|
||||
interface IMikRomManager
|
||||
{
|
||||
String hello();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
可以通过反射获取`ServiceManager`类,调用该类的`getService`函数得到mikrom的系统服务,将返回的结果转换为刚刚定义的接口对象,最后调用目标函数拿到结果。实现代码如下。
|
||||
|
||||
```java
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
Class localClass = null;
|
||||
try {
|
||||
localClass = Class.forName("android.os.ServiceManager");
|
||||
Method getServiceMethod = localClass.getMethod("getService", new Class[] {String.class});
|
||||
if(getServiceMethod != null) {
|
||||
Object objResult = getServiceMethod.invoke(localClass, new Object[]{"mikrom"});
|
||||
if (objResult != null) {
|
||||
IBinder binder = (IBinder) objResult;
|
||||
IMikRomManager iMikRom = IMikRomManager.Stub.asInterface(binder);
|
||||
String msg= iMikRom.hello();
|
||||
Log.i("MainActivity", "msg: " + msg);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
最后成功输出结果如下。
|
||||
|
||||
```
|
||||
cn.mik.myservicedemo I/MainActivity: msg: hello mikrom service
|
||||
```
|
||||
|
||||
## 6.5 修改APP默认权限
|
||||
|
||||
### 6.5.1 APP权限介绍
|
||||
|
||||
|
||||
|
||||
### 6.5.2 APP权限的源码跟踪
|
||||
|
||||
|
||||
|
||||
### 6.5.3 AOSP10下的默认权限修改
|
||||
|
||||
|
||||
|
||||
## 6.6 进程注入器
|
||||
|
||||
|
||||
|
||||
## 6.7 修改APP默认权限
|
||||
|
||||
### 6.7.1 APP权限介绍
|
||||
|
||||
|
||||
|
||||
### 6.7.2 APP权限的源码跟踪
|
||||
|
||||
|
||||
|
||||
### 6.7.3 AOSP10下的默认权限修改
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user