在 android M 以上,MediaRecorder 录音时音源设置为 VOICE_CALL,开始录音时会抛出权限异常
12-04 10:34:41.808 545 2254 D AudioRecord: set(): 0xe90ba000, inputSource 4, sampleRate 44100, format 0x1, channelMask 0x10, frameCount 2048, notificationFrames 1024, sessionId 0, transferType 0, flags 0, opPackageName cn.wangy.contacts uid 10059, pid 1917 12-04 10:34:41.814 409 2559 W ServiceManager: Permission failure: android.permission.CAPTURE_AUDIO_OUTPUT from uid=10059 pid=1917 12-04 10:34:41.815 409 2559 D PermissionCache: checking android.permission.CAPTURE_AUDIO_OUTPUT for uid=10059 => denied (548 us) 12-04 10:34:41.815 409 2559 E : Request requires android.permission.CAPTURE_AUDIO_OUTPUT 12-04 10:34:41.815 409 2559 E AudioFlinger: createRecord() checkRecordThread_l failed 12-04 10:34:41.815 545 2254 E IAudioFlinger: createRecord returned error -22 12-04 10:34:41.815 545 2254 E AudioRecord: AudioFlinger could not create record track, status: -22 12-04 10:34:41.816 545 2254 E StagefrightRecorder: audio source is not initialized 12-04 10:34:41.816 545 2254 D MPEG4Writer: reset+ 1081 12-04 10:34:41.816 1917 1917 E MediaRecorder: start failed: -2147483648 12-04 10:34:41.816 1917 1917 W System.err: java.lang.RuntimeException: start failed. 12-04 10:34:41.825 1917 1917 W System.err: at android.media.MediaRecorder.start(Native Method)
方法一,给 app 增加 sharedUserId=“android.uid.system”,并使用系统签名
方法二,屏蔽系统源码,跳过权限检查
通过全局搜索,发现权限判断竟然在 c 中,通过 pid 和 vid 来检查
frameworks\av\services\audiopolicy\service\AudioPolicyInterfaceImpl.cpp
frameworks\av\services\audioflinger\ServiceUtilities.cpp
android 8.1
注释 AudioPolicyInterfaceImpl.cpp 中 switch 语句块 status = PERMISSION_DENIED;
或者修改 ServiceUtilities.cpp 中 captureAudioOutputAllowed() 返回 true
if (status == NO_ERROR) { // enforce permission (if any) required for each type of input switch (inputType) { case AudioPolicyInterface::API_INPUT_LEGACY: break; case AudioPolicyInterface::API_INPUT_TELEPHONY_RX: // FIXME: use the same permission as for remote submix for now. case AudioPolicyInterface::API_INPUT_MIX_CAPTURE: if (!captureAudioOutputAllowed(pid, uid)) { ALOGE("getInputForAttr() permission allowed: capture allowed"); //cczheng annotation for don't check android.Manifest.permission.CAPTURE_AUDIO_OUTPUT /*ALOGE("getInputForAttr() permission denied: capture not allowed"); status = PERMISSION_DENIED;*/ } break; case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: if (!modifyAudioRoutingAllowed()) { ALOGE("getInputForAttr() permission denied: modify audio routing not allowed"); status = PERMISSION_DENIED; } break; case AudioPolicyInterface::API_INPUT_INVALID: default: LOG_ALWAYS_FATAL("getInputForAttr() encountered an invalid input type %d", (int)inputType); } }
android 9.0
9.0 中 AudioPolicyInterfaceImpl.cpp 在 switch 语句块前新增加了包名判断,上面的报错权限就是从这里打印的,注释如下
// check calling permissions //cczheng annotation for don't check android.Manifest.permission.CAPTURE_AUDIO_OUTPUT /*if (!recordingAllowed(opPackageName, pid, uid)) { ALOGE("%s permission denied: recording not allowed for uid %d pid %d", __func__, uid, pid); return PERMISSION_DENIED; } if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK || attr->source == AUDIO_SOURCE_VOICE_DOWNLINK || attr->source == AUDIO_SOURCE_VOICE_CALL) && !captureAudioOutputAllowed(pid, uid)) { return PERMISSION_DENIED; }*/ if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed(pid, uid)) { return BAD_VALUE; } sp<AudioPolicyEffects>audioPolicyEffects; { status_t status; AudioPolicyInterface::input_type_t inputType; Mutex::Autolock _l(mLock); { AutoCallerClear acc; // the audio_in_acoustics_t parameter is ignored by get_input() status = mAudioPolicyManager->getInputForAttr(attr, input, session, uid, config, flags, selectedDeviceId, &inputType, portId); } audioPolicyEffects = mAudioPolicyEffects; if (status == NO_ERROR) { // enforce permission (if any) required for each type of input switch (inputType) { case AudioPolicyInterface::API_INPUT_LEGACY: break; case AudioPolicyInterface::API_INPUT_TELEPHONY_RX: // FIXME: use the same permission as for remote submix for now. case AudioPolicyInterface::API_INPUT_MIX_CAPTURE: if (!captureAudioOutputAllowed(pid, uid)) { ALOGE("getInputForAttr() permission allowed: capture allowed"); //cczheng annotation for don't check android.Manifest.permission.CAPTURE_AUDIO_OUTPUT /*ALOGE("getInputForAttr() permission denied: capture not allowed"); status = PERMISSION_DENIED;*/ } break; case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: if (!modifyAudioRoutingAllowed()) { ALOGE("getInputForAttr() permission denied: modify audio routing not allowed"); status = PERMISSION_DENIED; } break; case AudioPolicyInterface::API_INPUT_INVALID: default: LOG_ALWAYS_FATAL("getInputForAttr() encountered an invalid input type %d", (int)inputType); } }