系统版本: Ubuntu 22.04 lts
AOSP分支: android-16.0.0_r4
本文将介绍如何在AOSP16中新增并使用一个运行时系统权限。
注意: 本文章将基于 实战Android Framework: 新增一个系统服务 进行修改。
一 新增权限声明
首先我们要在系统的AndroidManifest.xml中新增一个权限声明,打开AOSP16/frameworks/base/core/res/AndroidManifest.xml,新增:
xml
<!-- Permission required to use JYCBatteryService
<p>Protection level: dangerous
@FlaggedApi(android.os.Flags.FLAG_JYC_BATTERY_SERVICE_ENABLED)
-->
<permission android:name="android.permission.JYC_BATTERY_PERMISSION"
android:protectionLevel="dangerous"
android:featureFlag="android.os.jyc_battery_service_enabled" />
注意: 这里使用的
featureFlag是在 实战Android Framework: 新增一个系统服务 中新增的Aconfig标志,并且我们将protectionLevel标记为了dangerous,这意味着第三方应用不光需要在自己的AndroidManifest.xml中声明这个权限,并且需要在运行时申请这个权限,想知道这个protectionLevel可以标记为哪些并且它们有什么区别可以查看 Android权限。
之后我们需要进行编译:
Shell
m update-api
二 在系统服务中检查权限
打开在 实战Android Framework: 新增一个系统服务 中写好的JYCBatteryService,在getBattery方法中,增加权限需求:
Java
@Override
public int getBattery() {
mContext.enforceCallingOrSelfPermission(
"android.permission.JYC_BATTERY_PERMISSION",
"Need JYC_BATTERY_PERMISSION to access Jyc Battery Service");
BatteryManagerInternal bmi = LocalServices.getService(BatteryManagerInternal.class);
if (bmi != null) {
return bmi.getBatteryLevel();
}
return -1;
}
之后进行编译即可:
Shell
m
三 验证权限是否新增成功
编译完成之后,我们可以运行模拟器,然后输入ADB命令查看权限是否已经生效:
Shell
adb shell pm list permissions | grep JYC_BATTERY_PERMISSION
之后我们可以看到输出:
Shell
permission:android.permission.JYC_BATTERY_PERMISSION
这意味着我们已经成功新增了一个权限
四 在第三方App中申请权限
首先如果我们没有进行任何修改,直接使用对应方法,应用则会崩溃,Logcat中可以看到报错信息:
Log
E FATAL EXCEPTION: main (Fix with AI)
Process: com.jyc.testapplication, PID: 4492
java.lang.SecurityException: Need JYC_BATTERY_PERMISSION to access Jyc Battery Service: Neither user 10120 nor current process has android.permission.JYC_BATTERY_PERMISSION.
我们先修改AndroidManifest.xml,增加权限声明:
xml
<uses-permission android:name="android.permission.JYC_BATTERY_PERMISSION" />
之后修改应用的源码:
Kotlin
package com.jyc.testapplication
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.jycservice.JycBatteryManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat
import com.jyc.testapplication.ui.theme.TestApplicationTheme
class MainActivity : ComponentActivity() {
private val batteryLevelText = mutableStateOf("Loading...")
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
readBatteryLevel()
} else {
batteryLevelText.value = "Permission Denied"
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkPermissionAndRead()
enableEdgeToEdge()
setContent {
TestApplicationTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = batteryLevelText.value,
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
private fun checkPermissionAndRead() {
val permission = "android.permission.JYC_BATTERY_PERMISSION"
when {
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED -> {
readBatteryLevel()
}
else -> {
requestPermissionLauncher.launch(permission)
}
}
}
private fun readBatteryLevel() {
try {
val jycManager = getSystemService("jyc_battery") as JycBatteryManager
batteryLevelText.value = jycManager.batteryLevel.toString()
} catch (e: Exception) {
batteryLevelText.value = "Error: ${e.message}"
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Battery is $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
TestApplicationTheme {
Greeting("Android")
}
}
生成并安装应用,打开之后可以看到权限申请:

允许之后,可以看到调用成功:
