最近遇到一个问题,蓝牙键盘的静音键失效,系统在播放音乐的时候,但是静音图标可以正常显示,于是我追溯了一下从input keyevent VOLUME_MUTE 到audio的前半段过程如下
Input.java:
public static void main(String[] args) {
(new Input()).run(args);
}
private void run(String[] args) {
else if (command.equals("keyevent")) {
if (length >= 2) {
final boolean longpress = "--longpress".equals(args[index + 1]);
final int start = longpress ? index + 2 : index + 1;
inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
if (length > start) {
for (int i = start; i < length; i++) {
int keyCode = KeyEvent.keyCodeFromString(args[i]);
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
}
Log.i(TAG, "matt-void run ");
sendKeyEvent(inputSource, keyCode, longpress);
}
return;
}
}
}
}
private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
long now = SystemClock.uptimeMillis();
Log.i(TAG, "matt-sendKeyEvent: ");
injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
if (longpress) {
injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
inputSource));
}
injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
}
InputManagerService.java:
private void injectKeyEvent(KeyEvent event) {
Log.i(TAG, "matt-injectKeyEvent: " + event);
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
public boolean injectInputEvent(InputEvent event, int mode) {
return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
}
private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
Slog.e(TAG, "matt-injectInputEventInternal");
if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
&& mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
&& mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
throw new IllegalArgumentException("mode is invalid");
}
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
final int result;
try {
result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
} finally {
Binder.restoreCallingIdentity(ident);
}
switch (result) {
case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
throw new SecurityException(
"Injecting to another application requires INJECT_EVENTS permission");
case INPUT_EVENT_INJECTION_SUCCEEDED:
return true;
case INPUT_EVENT_INJECTION_TIMED_OUT:
Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
return false;
case INPUT_EVENT_INJECTION_FAILED:
default:
Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
return false;
}
}
com_android_server_input_InputManagerService.cpp:
static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid,
jint syncMode, jint timeoutMillis, jint policyFlags) {
NativeInputManager* im = reinterpret_cast
if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
KeyEvent keyEvent;
status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
if (status) {
jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
return INPUT_EVENT_INJECTION_FAILED;
}
return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
& keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,
uint32_t(policyFlags));
} else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
if (!motionEvent) {
jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
return INPUT_EVENT_INJECTION_FAILED;
}
return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,
uint32_t(policyFlags)); //跑到了这里
} else {
jniThrowRuntimeException(env, "Invalid input event type.");
return INPUT_EVENT_INJECTION_FAILED;
}
}
inputdispatcher.cpp:
int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags) {
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
ALOGE("matt-inputdispatcher-injectInputEvent");
const KeyEvent* keyEvent = static_cast
int32_t action = keyEvent->getAction();
if (! validateKeyEvent(action)) {
return INPUT_EVENT_INJECTION_FAILED;
}
if (needWake) {
ALOGE(" matt-mLooper->wake();");
mLooper->wake();
}
}
之后怎么跳到下面的地方真的不知道
PhoneWindow.java:
public boolean dispatchKeyEvent(KeyEvent event) {
Log.d(TAG, "matt-dispatchKeyEvent-PhoneWindow.java ");
return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
: PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
Log.d(TAG, "matt-before switch (keyCode) ");
int direction = 0;
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
direction = AudioManager.ADJUST_RAISE;
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
direction = AudioManager.ADJUST_LOWER;
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
Log.d(TAG, "matt-case KeyEvent.KEYCODE_VOLUME_MUTE ");
direction = AudioManager.ADJUST_TOGGLE_MUTE;
break;
}
if (mMediaController != null) {
Log.d(TAG, "matt- if (mMediaController != null) ");
mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
} else {
MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy( //跑到了这里
mVolumeControlStreamType, direction,
AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE
| AudioManager.FLAG_FROM_KEY);
}
}
MediaSessionLegacyHelper.java:
public void sendAdjustVolumeBy(int suggestedStream, int delta, int flags) {
mSessionManager.dispatchAdjustVolume(suggestedStream, delta, flags);
if (DEBUG) {
Log.d(TAG, "dispatched volume adjustment");
}
}
MediaSessionManager.java:
public void dispatchAdjustVolume(int suggestedStream, int direction, int flags) {
try {
mService.dispatchAdjustVolume(suggestedStream, direction, flags);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send adjust volume.", e);
}
}
MediaSessionService.java:
public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
Log.d(TAG, "matt-MediaSessionService.java-dispatchAdjustVolume ");
try {
synchronized (mLock) {
MediaSessionRecord session = mPriorityStack
.getDefaultVolumeSession(mCurrentUserId);
dispatchAdjustVolumeLocked(suggestedStream, delta, flags, session);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
MediaSessionRecord session) {
// if (DEBUG) {
String description = session == null ? null : session.toString();
Log.d(TAG, "matt-dispatchAdjustVolumeLocked-Adjusting session " + description + " by " + direction + ". flags="
+ flags + ", suggestedStream=" + suggestedStream);
// }
boolean preferSuggestedStream = false;
if (isValidLocalStreamType(suggestedStream)
&& AudioSystem.isStreamActive(suggestedStream, 0)) {
preferSuggestedStream = true;
}
if (session == null || preferSuggestedStream) {
Log.d(TAG, "matt- if (session == null"); //最后走了这边
if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
&& !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
if (DEBUG) {
Log.d(TAG, "No active session to adjust, skipping media only volume event");
}
return;
}
try {
String packageName = getContext().getOpPackageName();
mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
flags, packageName, TAG);
} catch (RemoteException e) {
Log.e(TAG, "Error adjusting default volume.", e);
}
} else {
Log.d(TAG, "matt- else");
session.adjustVolume(direction, flags, getContext().getPackageName(),
UserHandle.myUserId(), true);
}
}
AudioService.java :
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller) {
adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
caller, Binder.getCallingUid());
}
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller, int uid) {
Log.d(TAG, "matt-adjustSuggestedStreamVolume() stream=" + suggestedStreamType
+ ", flags=" + flags + ", caller=" + caller);
int streamType;
boolean isMute = isMuteAdjust(direction);
Log.d(TAG, "matt-adjustSuggestedStreamVolume+isMute=%d",isMute);
if (mVolumeControlStream != -1) {
streamType = mVolumeControlStream;
} else {
streamType = getActiveStreamType(suggestedStreamType);
}
ensureValidStreamType(streamType);
final int resolvedStream = mStreamVolumeAlias[streamType];
// Play sounds on STREAM_RING only.
if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
resolvedStream != AudioSystem.STREAM_RING) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
// For notifications/ring, show the ui before making any adjustments
// Don't suppress mute/unmute requests
if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
direction = 0;
flags &= ~AudioManager.FLAG_PLAY_SOUND;
flags &= ~AudioManager.FLAG_VIBRATE;
if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
}
Log.d(TAG, "matt-adjustSuggestedStreamVolume+2");
adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
}
private void adjustStreamVolume(int streamType, int direction, int flags,
String callingPackage, String caller, int uid) {
if (mUseFixedVolume) {
return;
}
Log.e(TAG, "matt-adjustStreamVolume() stream=" + streamType + ", dir=" + direction
+ ", flags=" + flags + ", caller=" + caller);
ensureValidDirection(direction);
ensureValidStreamType(streamType);
boolean isMuteAdjust = isMuteAdjust(direction);
Log.e(TAG, "matt-adjustStreamVolume+isMuteAdjust="+isMuteAdjust);
if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
return;
}
if (isMuteAdjust) {
boolean state;
if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
state = !streamState.mIsMuted;
} else {
state = direction == AudioManager.ADJUST_MUTE;
}
Log.e(TAG, "matt-adjustStreamVolume-state="+state);
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioMute(state);
}
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (streamTypeAlias == mStreamVolumeAlias[stream]) {
if (!(readCameraSoundForced()
&& (mStreamStates[stream].getStreamType()
== AudioSystem.STREAM_SYSTEM_ENFORCED))) {
mStreamStates[stream].mute(state);
}
}
}
}
}
public void mute(boolean state) {
boolean changed = false;
synchronized (VolumeStreamState.class) {
if (state != mIsMuted) {
changed = true;
mIsMuted = state;
// Set the new mute volume. This propagates the values to
// the audio system, otherwise the volume won't be changed
// at the lower level.
Log.e(TAG, "matt-mute");
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
SENDMSG_QUEUE,
0,
0,
this, 0);
}
}
Log.e(TAG, "matt-mute+1");
if (changed) {
// Stream mute changed, fire the intent.
Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
sendBroadcastToAll(intent);
}
}
静音
02-20 14:35:08.551 1655 2894 D MediaSessionService: matt-MediaSessionService.java-dispatchAdjustVolume
02-20 14:35:08.551 1655 2894 D MediaSessionService: matt-dispatchAdjustVolumeLocked-Adjusting session null by 101. flags=4113, suggestedStream=-2147483648
02-20 14:35:08.551 1655 2894 D MediaSessionService: matt- if (session == null
02-20 14:35:08.551 1655 2894 E AudioService: matt-adjustSuggestedStreamVolume() stream=-2147483648, flags=4113, caller=MediaSessionService
02-20 14:35:08.551 1655 2894 E AudioService: matt-adjustSuggestedStreamVolume+isMute=true
02-20 14:35:08.555 1655 2894 E AudioService: matt-adjustSuggestedStreamVolume+2
02-20 14:35:08.555 1655 2894 E AudioService: matt-adjustStreamVolume() stream=2, dir=101, flags=4113, caller=MediaSessionService
02-20 14:35:08.555 1655 2894 E AudioService: matt-adjustStreamVolume+isMuteAdjust=true
02-20 14:35:08.556 1655 2894 E AudioService: matt-adjustStreamVolume-state=true
02-20 14:35:08.556 1655 2894 E AudioService: matt-mute
02-20 14:35:08.556 1655 2894 E AudioService: matt-mute+1
02-20 14:35:08.557 1655 2894 E AudioService: matt-mute
02-20 14:35:08.557 1655 2894 E AudioService: matt-mute+1
02-20 14:35:08.558 1655 2894 E AudioService: matt-mute
02-20 14:35:08.558 1655 2894 E AudioService: matt-mute+1
02-20 14:35:08.558 1655 2894 E AudioService: matt-mute
02-20 14:35:08.558 1655 2894 E AudioService: matt-mute+1
取消静音
02-20 14:35:23.078 1655 2462 D MediaSessionService: matt-MediaSessionService.java-dispatchAdjustVolume
02-20 14:35:23.078 1655 2462 D MediaSessionService: matt-dispatchAdjustVolumeLocked-Adjusting session null by 101. flags=4113, suggestedStream=-2147483648
02-20 14:35:23.078 1655 2462 D MediaSessionService: matt- if (session == null
02-20 14:35:23.078 1655 2462 E AudioService: matt-adjustSuggestedStreamVolume() stream=-2147483648, flags=4113, caller=MediaSessionService
02-20 14:35:23.078 1655 2462 E AudioService: matt-adjustSuggestedStreamVolume+isMute=true
02-20 14:35:23.083 1655 2462 E AudioService: matt-adjustSuggestedStreamVolume+2
02-20 14:35:23.083 1655 2462 E AudioService: matt-adjustStreamVolume() stream=2, dir=101, flags=4113, caller=MediaSessionService
02-20 14:35:23.083 1655 2462 E AudioService: matt-adjustStreamVolume+isMuteAdjust=true
02-20 14:35:23.083 1655 2462 E AudioService: matt-adjustStreamVolume-state=false
02-20 14:35:23.083 1655 2462 E AudioService: matt-mute
02-20 14:35:23.083 1655 2462 E AudioService: matt-mute+1
02-20 14:35:23.086 1655 2462 E AudioService: matt-mute
02-20 14:35:23.086 1655 2462 E AudioService: matt-mute+1
02-20 14:35:23.086 1655 2462 E AudioService: matt-mute
02-20 14:35:23.086 1655 2462 E AudioService: matt-mute+1
02-20 14:35:23.088 1655 2462 E AudioService: matt-mute
02-20 14:35:23.088 1655 2462 E AudioService: matt-mute+1
MediaController.java :
public void adjustVolume(int direction, int flags) {
try {
mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName());
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
}
}
MediaSessionCompat.java:
public void adjustVolume(int direction, int flags, String packageName) {
MediaSessionImplBase.this.adjustVolume(direction, flags);
}
private void adjustVolume(int direction, int flags) {
if (mVolumeType == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
if (mVolumeProvider != null) {
Log.d("matt", " MediaSessionCompat.java-adjustVolume-if");
mVolumeProvider.onAdjustVolume(direction);
}
} else {
Log.d("matt", " MediaSessionCompat.java-adjustVolume-else");
mAudioManager.adjustStreamVolume(direction, mLocalStream, flags);
}
}
MediaSessionRecord.java:
public void adjustVolume(int direction, int flags, String packageName) {
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
MediaSessionRecord.this.adjustVolume(direction, flags, packageName, uid, false);
} finally {
Binder.restoreCallingIdentity(token);
}
}
public void adjustVolume(int direction, int flags, String packageName, int uid,
boolean useSuggested) {
int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
if (isPlaybackActive(false) || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
// Adjust the volume with a handler not to be blocked by other system service.
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
postAdjustLocalVolume(stream, direction, flags, packageName, uid, useSuggested,
previousFlagPlaySound);
} else {
if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
// Nothing to do, the volume cannot be changed
return;
}
if (direction == AudioManager.ADJUST_TOGGLE_MUTE
|| direction == AudioManager.ADJUST_MUTE
|| direction == AudioManager.ADJUST_UNMUTE) {
Log.w(TAG, "Muting remote playback is not supported");
return;
}
mSessionCb.adjustVolume(direction);
int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
mOptimisticVolume = volumeBefore + direction;
mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume));
mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
if (volumeBefore != mOptimisticVolume) {
pushVolumeUpdate();
}
mService.notifyRemoteVolumeChanged(flags, this);
if (DEBUG) {
Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is "
+ mMaxVolume);
}
}
}