Android音频之车载录音权限
android.permission.RECORD_AUDIO
权限
android.permission.RECORD_AUDIO
是 Android 系统中用于访问设备麦克风并捕获音频数据的权限。该权限属于 危险权限(Dangerous Permission),需要用户明确授权才能使用。
一、权限声明
在 Android 应用的 AndroidManifest.xml
文件中,需要显式声明该权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
二、权限类别
- 危险权限
RECORD_AUDIO
属于危险权限,需要通过运行时权限请求获得用户的授权。- 在 Android 6.0 (API 23) 及以上版本,声明该权限后,应用必须在运行时动态申请权限。
- 权限分组
- 该权限属于 麦克风权限组(
android.permission-group.MICROPHONE
)。
- 该权限属于 麦克风权限组(
三、使用场景
1. 典型功能
- 音频录制:录制用户的语音或环境音。
- 音频处理:实时音频处理,如降噪、语音识别等。
- 多媒体应用:如录音机、视频录制、视频通话、直播应用等。
2. 与相关API结合使用
MediaRecorder
:录制音频或视频。AudioRecord
:低级音频录制接口,用于实时音频处理。SpeechRecognizer
:语音识别接口,通常需要录音权限。MediaProjection
:用于录制屏幕时捕获音频。
四、权限申请
在 Android 6.0 (API 23) 及以上版本,运行时需要动态申请权限。
应用自申请
// 1. 检查权限 在使用录音功能前,检查是否已经获得录音权限:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
// 权限未被授予
// 2. 请求权限 向用户请求录音权限:
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE);
}
// 3. 权限结果回调 处理用户权限请求的结果:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限已被授予
} else {
// 权限被拒绝
}
}
}
五、系统限制
1. 录音权限的作用
在 Android 系统中,即使应用获得了 RECORD_AUDIO
权限,系统仍会对音频数据的访问进行一定限制:
- 如果应用未获得权限,录音接口(如
AudioRecord
或MediaRecorder
)的返回数据可能为零值数据。 - 在部分场景下,系统可能通过 音频策略(AudioPolicy)来限制录音功能,例如屏蔽后台录音等。
2. 多权限交互
RECORD_AUDIO
权限可能与以下权限配合使用:
android.permission.MODIFY_AUDIO_SETTINGS
:允许修改音频设置。android.permission.CAPTURE_AUDIO_OUTPUT
:捕获设备音频输出,但通常仅限于系统应用。android.permission.BLUETOOTH
:通过蓝牙设备录音时可能需要。
3. 后台录音限制
- 从 Android 10(API 29)开始,后台录音被系统进一步限制,除非应用具有特殊权限(如
FOREGROUND_SERVICE
)。 - 应用必须运行在前台(显示通知)才能录音。
六、典型问题
1. 权限未声明
- 错误:
java.lang.SecurityException: Permission Denial: requires android.permission.RECORD_AUDIO
- 解决方法:在
AndroidManifest.xml
中添加权限声明。
2. 权限未授予
- 错误:
SecurityException: App does not have permission to record audio
- 解决方法:在运行时动态申请权限。
3. 音频数据为零
- 原因:
- 应用未获得录音权限。
- 系统通过音频策略屏蔽了音频输入(如麦克风被禁用)。
- 解决方法:确认权限状态并确保麦克风功能可用。
七、隐私保护和敏感权限政策
Android 系统对 RECORD_AUDIO
权限有严格的隐私保护措施:
- 权限提示
- 当应用申请录音权限时,系统会提示用户,该权限可访问麦克风捕获环境声音。
- 录音指示器
- 从 Android 12(API 31)开始,系统在屏幕顶部会显示绿色的麦克风使用指示器,提醒用户某些应用正在访问麦克风。
- 权限开关
- 用户可以在系统设置中随时禁用麦克风权限。
八、系统管控动态权限
JAVA 代码示例
public void grantRecordAudioPermission(String packageName) {
try {
String permission = android.Manifest.permission.RECORD_AUDIO;
// 使用 PackageManager 授予权限
mContext.getPackageManager().grantRuntimePermission(packageName, permission, UserHandle.SYSTEM);
// 验证权限是否成功授予
int permissionStatus = mContext.getPackageManager().checkPermission(permission, packageName);
if (permissionStatus == PackageManager.PERMISSION_GRANTED) {
Log.d("PermissionControl", "录音权限已授予给: " + packageName);
} else {
Log.e("PermissionControl", "录音权限授予失败!");
}
} catch (Exception e) {
Log.e("PermissionControl", "权限授予时出错: " + e.getMessage());
}
}
public void revokeRecordAudioPermission(String packageName) {
try {
String permission = android.Manifest.permission.RECORD_AUDIO;
// 使用 PackageManager 撤销权限
mContext.getPackageManager().revokeRuntimePermission(packageName, permission, UserHandle.SYSTEM);
// 验证权限是否成功撤销
int permissionStatus = mContext.getPackageManager().checkPermission(permission, packageName);
if (permissionStatus == PackageManager.PERMISSION_DENIED) {
Log.d("PermissionControl", "录音权限已撤销: " + packageName);
} else {
Log.e("PermissionControl", "录音权限撤销失败!");
}
} catch (Exception e) {
Log.e("PermissionControl", "权限撤销时出错: " + e.getMessage());
}
}
String packageName = "com.example.audiolp";
grantRecordAudioPermission(packageName);
revokeRecordAudioPermission(packageName);
在上例中,com.example.audiolp
应用没有录音权限的时候,在创建录音器的时候会报错。如下:
12-27 17:24:44.226 546 823 E ServiceUtilities: Request requires android.permission.RECORD_AUDIO
12-27 17:24:44.226 546 823 E AudioPolicyIntefaceImpl: getInputForAttr permission denied: recording not allowed for uid 10035 pid 12765
12-27 17:24:44.226 546 823 E AudioFlinger: createRecord() getInputForAttr return error -1
具体代码位置在 frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
文件中 AudioPolicyService::getInputForAttr()
函数中, recordingAllowed()
处会报错,从而启动录音失败。
应用在成功录音之后,再把权限关闭revokeRecordAudioPermission
, audioserver会收到状态通知,设置 setRecordSilenced(portId, silenced)
,并停止录音,。如下:
12-27 17:51:07.888 546 823 I AF::OpRecordAudioMonitor: OP_RECORD_AUDIO missing, silencing record uid10035 pack:com.example.audiolp
12-27 17:27:27.276 546 1524 E AudioPolicyService: audioflinger2 updateUidStates_l allowCapture=0
12-27 17:27:27.276 546 1524 V APM_AudioPolicyManager: setAppState(portId:93, state:0)
12-27 17:27:27.328 546 822 V APM_AudioPolicyManager: stopInput portId 93
12-27 17:27:27.333 546 822 V APM_AudioPolicyManager: resetInputDevice() releaseAudioPatch returned 0
12-27 17:27:27.334 546 822 V APM_AudioPolicyManager: releaseInput portId 93
12-27 17:27:27.334 546 822 V APM_AudioPolicyManager: releaseInput 118
12-27 17:27:27.334 546 822 V APM_AudioPolicyManager: closeInput(118)
12-27 17:27:27.539 546 822 V APM_AudioPolicyManager: releaseInput exit
具体代码位置在 frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
文件中 AudioPolicyService::updateUidStates_l()
函数中, AudioPolicyService::setAppState_l()
。
adb查看应用权限
adb shell dumpsys package com.example.audiolp
adb shell dumpsys package com.chinatsp.audiolp |grep RECORD_AUDIO