记一次 Android 系统铃声不响的解决过程
给主力机Phoenix刷入最新的EvolutionX系统(20210214版本)之后,使用了一两天,看起来一切正常,直到我发现自己漏接了3个电话。。。(连来电震动都忘了开,罪过,罪过)
试着用别人的手机打电话过来,铃声总是不响。奇怪的是,通知声音和闹钟声音都是正常的,这很令人疑惑。
在排除勿扰模式的影响之后,尝试替换其他铃声(包括系统内置铃声),仍然没能解决问题。
没办法,只能logcat咯。。。
抓取来电时产生的log,搜索关键词ringtone
,最后我关注到这一行:
02-19 22:59:10.789 1748 3208 I Telecom: Ringer: startRinging: skipping because ringer would not be audible. isVolumeOverZero=true, shouldRingForContact=true, isRingtonePresent=false: NCSSF.ac->ICFG.sf->ICFG.sf->ICFG.sf->CAMSM.pM_2002@Bfc
以上这段log直译:正在跳过,因为无法听到铃声
。
顺带打印的三个参数为:音量是否大于0:True,该联系人是否应该响铃:True,铃声是否存在:False
。
通过日志文本内容,从EvolutionX项目源码中全局搜索:
/* https://github.com/Evolution-X/packages_services_Telecomm/blob/5f75e65fd8b65ba3a1759d75a72440f5e27e755b/src/com/android/server/telecom/Ringer.java#L365 */
if (isRingerAudible) {
// 略...
} else {
String reason = String.format(
"isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s",
isVolumeOverZero, shouldRingForContact, isRingtonePresent);
Log.i(this, "startRinging: skipping because ringer would not be audible. " + reason);
Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " + reason);
effect = mDefaultVibrationEffect;
}
isRingerAudible
参数定义在同文件的第319行:
/* https://github.com/Evolution-X/packages_services_Telecomm/blob/5f75e65fd8b65ba3a1759d75a72440f5e27e755b/src/com/android/server/telecom/Ringer.java#L319 */
boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent;
timer.record("isRingerAudible");
可以看出,只有isVolumeOverZero
、shouldRingForContact
、isRingtonePresent
都为真时才会响铃。
那么就可以确定问题出在系统没有找到铃声文件了。
查看isRingtonePresent
的定义,向上找到getRingtone
方法,该方法定义如下:
/* https://github.com/Evolution-X/packages_services_Telecomm/blob/58d940e14cd89d7e0b56ed0e904ae0b53eba30e9/src/com/android/server/telecom/RingtoneFactory.java#L67 */
public Ringtone getRingtone(Call incomingCall,
@Nullable VolumeShaper.Configuration volumeShaperConfig) {
// Use the default ringtone of the work profile if the contact is a work profile contact.
Context userContext = isWorkContact(incomingCall) ?
getWorkProfileContextForUser(mCallsManager.getCurrentUserHandle()) :
getContextForUserHandle(mCallsManager.getCurrentUserHandle());
Uri ringtoneUri = incomingCall.getRingtone();
Ringtone ringtone = null;
if(ringtoneUri != null && userContext != null) {
// Ringtone URI is explicitly specified. First, try to create a Ringtone with that.
ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri, volumeShaperConfig);
}
if(ringtone == null) {
// Contact didn't specify ringtone or custom Ringtone creation failed. Get default
// ringtone for user or profile.
Context contextToUse = hasDefaultRingtoneForUser(userContext) ? userContext : mContext;
Uri defaultRingtoneUri;
if (UserManager.get(contextToUse).isUserUnlocked(contextToUse.getUserId())) {
defaultRingtoneUri =
RingtoneManager.getActualDefaultRingtoneUriForPhoneAccountHandle(
contextToUse,
RingtoneManager.TYPE_RINGTONE,
incomingCall.getTargetPhoneAccount());
} else {
defaultRingtoneUri = Settings.System.DEFAULT_RINGTONE_URI;
}
if (defaultRingtoneUri == null) {
return null;
}
ringtone = RingtoneManager.getRingtone(
contextToUse, defaultRingtoneUri, volumeShaperConfig);
}
if (ringtone != null) {
ringtone.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build());
}
return ringtone;
}
简单分析一下该方法:关于工作资料(work profile
)暂且不关注,先关注if(ringtone == null) {
这段语句块:如果对应联系人有特定的铃声的话,那么使用特定的铃声,否则使用默认铃声,如果没有设置默认铃声的话,那么getRingtone
方法返回null,也就导致isRingtonePresent
为假了。
那么就先试试给某个联系人设置一个特定来电铃声,看看会不会响铃。
结果是可以响铃。那么就可以确定问题出在系统找不到默认铃声了。
adb连接手机进行调试,通过settings命令,获取系统所有已经定义的键值:
phoenix:/ $ settings list system
accelerometer_rotation=0
accent_color=-15043608
adaptive_playback_timeout=30000
advanced_reboot=1
alarm_alert=content://0@media/external/audio/media/1641?title=alarm_clock1&canonical=1
alarm_alert_set=1
...
notification_sound=content://0@media/external/audio/media/1640?title=Meet&canonical=1
notification_sound_set=1
notification_sound_vib_screen_on=1
...
ringtone_89*****************9=content://0@media/external/audio/media/1639?title=Cloud&canonical=1
ringtone_89*****************2=content://0@media/external/audio/media/1639?title=Cloud&canonical=1
ringtone_set=1
ringtone_vibration_pattern=0
...
关注ringtone_89*****************9
和ringtone_89*****************2
这两个键,这应该是对应了双卡不同的铃声(EvolutionX这次更新带来了可以为两张SIM卡设置不同来电铃声的功能)。
于是我推测,这应该是双卡铃声功能带来的bug。用settings命令定义一个键为ringtone
的键值对:
phoenix:/ $ settings
Settings provider (settings) commands:
help
Print this help text.
get [--user <USER_ID> | current] NAMESPACE KEY
Retrieve the current value of KEY.
put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default]
Change the contents of KEY to VALUE.
TAG to associate with the setting.
{default} to set as the default, case-insensitive only for global/secure namespace
delete [--user <USER_ID> | current] NAMESPACE KEY
Delete the entry for KEY.
reset [--user <USER_ID> | current] NAMESPACE {PACKAGE_NAME | RESET_MODE}
Reset the global/secure table for a package with mode.
RESET_MODE is one of {untrusted_defaults, untrusted_clear, trusted_defaults}, case-insensitive
list [--user <USER_ID> | current] NAMESPACE
Print all defined keys.
NAMESPACE is one of {system, secure, global}, case-insensitive
255|phoenix:/ $ settings put system ringtone 'content://0@media/external/audio/media/1639?title=Cloud&canonical=1'
phoenix:/ $ settings list system
...
ringtone=content://0@media/external/audio/media/1639?title=Cloud&canonical=1
ringtone_89*****************9=content://0@media/external/audio/media/1639?title=Cloud&canonical=1
ringtone_89*****************2=content://0@media/external/audio/media/1639?title=Cloud&canonical=1
ringtone_set=1
ringtone_vibration_pattern=0
...
现在,问题彻底解决了。