请逐行分析下Android T 的AudioService.java中setMode函数 点击复制后,将打开C知道体验页
时间: 2023-06-13 21:05:01 浏览: 163
很抱歉,作为AI助手,我无法打开C知道的体验页。不过,我可以为您解释一下Android T的AudioService.java中setMode函数的逐行分析:
1. 首先,该函数的作用是设置音频模式。
2. 接下来,该函数会先判断输入的模式是否和当前的模式相同,如果相同则直接返回,不做任何处理。
3. 如果输入的模式和当前的模式不同,则会根据输入的模式进行相应的处理。
4. 首先,该函数会停止当前的音频播放,然后设置音频焦点的模式。
5. 接着,该函数会根据输入的模式设置相应的音频路由和音量。
6. 最后,该函数会发送一个广播通知系统音频模式已经改变。
总之,setMode函数的作用是设置音频模式,并根据输入的模式进行相应的处理,包括停止当前的音频播放、设置音频焦点的模式、设置音频路由和音量等。
相关问题
请逐行分析下Android T 的AudioService.java中setMode函数
好的,让我来逐行分析下Android T的AudioService.java中setMode函数。
```java
/**
* @see AudioManager#setMode(int)
*/
public void setMode(int mode, IBinder cb, String callingPackageName) {
enforceModifyAudioRoutingPermission();
synchronized (mConnectedDevices) {
final int newModeOwnerPid = Binder.getCallingPid();
final int newModeOwnerUid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
final boolean modeOwnerChanged = (mModeOwnerPid != newModeOwnerPid
|| mModeOwnerUid != newModeOwnerUid);
try {
setModeInt(mode, cb, callingPackageName, modeOwnerChanged, newModeOwnerPid,
newModeOwnerUid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
```
这个函数的作用是设置音频模式,它是实现了AudioManager类的setMode方法。
函数的第一个参数mode是要设置的音频模式。
函数的第二个参数cb是一个Binder对象,它可以在AudioFocusManager中使用,用来管理音频焦点。
函数的第三个参数callingPackageName是调用这个函数的应用程序的包名。
接下来是函数的实现。
首先,它调用enforceModifyAudioRoutingPermission()方法来检查是否有修改音频路由的权限。
然后,它使用synchronized关键字同步了mConnectedDevices,这是一个存储连接的设备信息的集合。
接着,它获取了调用这个函数的应用程序的PID和UID,以及清除了调用者的身份验证标识符。
接下来,它检查是否有新的模式所有者,并设置了一个用于检测模式所有者更改的标志。
最后,它调用了setModeInt方法来实际设置音频模式,传递了所有必要的参数,并在结束时恢复了调用者的身份验证标识符。
至此,Android T的AudioService.java中setMode函数的分析就结束了。
请逐行分析下AudioService.java中setMode函数
好的,我来分析一下AudioService.java中setMode函数的代码。首先,这个函数的作用是设置音频模式,具体而言,就是设置音频流的使用场景(比如是听音乐、打电话、玩游戏等),这会影响到音频系统的参数设置,比如音量、音效等。下面是这个函数的代码:
```
public int setMode(int mode, IBinder cb, String callingPackageName) {
if (DEBUG_MODE) {
Log.d(TAG, "setMode(" + mode + ")");
}
// Ensure the calling package name is valid, if specified.
if (callingPackageName != null) {
final int oldUid = Binder.getCallingUid();
final int newUid = getUidForPackage(callingPackageName);
if (newUid != oldUid && !isPrivileged(Binder.getCallingPid(), oldUid)) {
Log.e(TAG, "Cannot set mode from non privileged app: " + callingPackageName);
return AudioManager.MODE_INVALID;
}
}
// Permission check.
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "MODIFY_AUDIO_SETTINGS Permission Denial: setMode()");
return AudioManager.MODE_INVALID;
}
if (mode == AudioManager.MODE_INVALID) {
return AudioManager.MODE_INVALID;
}
int newModeOwnerPid = Binder.getCallingPid();
int newModeOwnerUid = Binder.getCallingUid();
synchronized (mSetModeDeathHandlers) {
if (cb == null) {
// synchronous call, clear death handler
mSetModeDeathHandlers.remove(newModeOwnerPid);
} else {
// asynchronous call, set death handler
try {
cb.linkToDeath(new SetModeDeathHandler(newModeOwnerPid, newModeOwnerUid, cb),
0 /* flags */);
} catch (RemoteException e) {
Log.w(TAG, "setMode() could not link to " + cb + " binder death");
return AudioManager.MODE_INVALID;
}
mSetModeDeathHandlers.put(newModeOwnerPid,
new SetModeDeathHandler(newModeOwnerPid, newModeOwnerUid, cb));
}
}
return onSetMode(mode, newModeOwnerPid, newModeOwnerUid, callingPackageName);
}
```
接下来逐行解释:
1. `if (DEBUG_MODE) { Log.d(TAG, "setMode(" + mode + ")"); }`
这个if语句判断是否需要打印调试信息。如果需要,则调用Log.d()函数输出调试信息,包括当前设置的音频模式(mode)。
2. `if (callingPackageName != null) { ... }`
这个if语句判断是否提供了调用者的包名。如果提供了,则检查调用者是否有足够的权限进行操作。具体而言,如果调用者不是系统特权应用程序(privileged app),则不允许设置音频模式,会返回错误码AudioManager.MODE_INVALID。
3. `if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) != PackageManager.PERMISSION_GRANTED) { ... }`
这个if语句检查当前调用者是否有修改音频设置的权限。如果没有,则返回错误码AudioManager.MODE_INVALID。
4. `if (mode == AudioManager.MODE_INVALID) { return AudioManager.MODE_INVALID; }`
这个if语句检查传入的音频模式是否合法。如果不合法,则直接返回错误码AudioManager.MODE_INVALID。
5. `int newModeOwnerPid = Binder.getCallingPid(); int newModeOwnerUid = Binder.getCallingUid();`
这两行代码获取当前调用者的进程ID和用户ID。
6. `synchronized (mSetModeDeathHandlers) { ... }`
这个synchronized语句块用于对mSetModeDeathHandlers对象加锁,保证多线程安全。mSetModeDeathHandlers是一个HashMap对象,用于存储SetModeDeathHandler对象(一个自定义的类,用于处理音频模式设置时Binder线程的死亡通知),以PID为键值。
7. `if (cb == null) { mSetModeDeathHandlers.remove(newModeOwnerPid); } else { ... }`
这个if语句判断是否需要设置死亡通知。如果不需要,则从mSetModeDeathHandlers中移除对应的SetModeDeathHandler对象。否则,需要将该对象添加到mSetModeDeathHandlers中,并且注册Binder线程的死亡通知。
8. `return onSetMode(mode, newModeOwnerPid, newModeOwnerUid, callingPackageName);`
最后,调用onSetMode函数处理音频模式设置。具体的实现在AudioService的子类AudioServiceInternal中。
阅读全文