[问题记录] Android裁剪Provision应用后无法打开开发者选项
最近在做RK平台的内置应用裁剪,按照需求最终决定了裁剪列表,大概减少了系统img包100M的体积。裁剪的列表如下:
LOCAL_OVERRIDES_PACKAGES += \
TelephonyProvider \
CalendarProvider \
WallpaperCropper \
DocumentsUI \
HTMLViewer \
QuickSearchBox \
MmsService \
DownloadProvider \
DownloadProviderUi \
SimAppDialog \
Contacts \
EasterEgg \
NfcNci \
Launcher3QuickStep \
Calendar \
PrintSpooler \
BasicDreams \
BuiltInPrintService \
MusicFX \
Telecom \
PrintRecommendationService \
ManagedProvisioning \
SoundPicker \
PhotoTable \
WAPPushManager \
LiveWallpapersPicker \
BookmarkProvider \
ExactCalculator \
TeleService \
WallpaperBackup \
BlockedNumberProvider \
UserDictionaryProvider \
DeskClock \
WallpaperPicker \
Provision
在后面几天的测试开发中,发现了一个问题:从原生设置中打开关于,点击版本号,无法打开开发者模式了。
解决方案
1.临时解决方案:查看 device_provisioned 的值。如果是0,则设置为1:
settings get global device_provisioned
settings put global device_provisioned 1
2. 根本解决方案:重新调整裁剪列表,不裁剪开机向导 Provision 这个应用。
解决过程
1.打开开发者选项有一个很明显的Toast,内容是“xxxx开发者xxxx”。于是直接在设置的源码中搜索 “开发者” 这个字段,应该可以找到对应的 string 资源和名称。
packages/apps/Settings# grep -nr "开发者"
res/values-zh-rCN/strings.xml:27: <item quantity="other">现在只需再执行 <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> 步操作即可进入开发者模式。</item>
res/values-zh-rCN/strings.xml:28: <item quantity="one">现在只需再执行 <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> 步操作即可进入开发者模式。</item>
res/values-zh-rCN/strings.xml:30: <string name="show_dev_on" msgid="2840850085134853754">"您现在处于开发者模式!"</string>
res/values-zh-rCN/strings.xml:31: <string name="show_dev_already" msgid="7041756429707644630">"您已处于开发者模式,无需进行此操作。"</string>
res/values-zh-rCN/strings.xml:32: <string name="dev_settings_disabled_warning" msgid="6971867026249671244">"请先启用开发者选项。"</string>
res/values-zh-rCN/strings.xml:2721: <string name="fullbackup_data_summary" msgid="971587401251601473">"自动远程备份设备数据(例如 WLAN 密码和通话记录)和应用数据(例如应用存储的设置和文件)。\n\n启用自动备份功能后,系统会定期远程保存设备和应用数据。应用数据可以是应用根据开发者设置保存的任何数据,包括可能比较敏感的数据(例如通讯录、邮件和照片)。"</string>
res/values-zh-rCN/strings.xml:4421: <string name="quick_settings_developer_tiles" msgid="7336007844525766623">"快捷设置开发者图块"</string>
res/values-zh-rCN/strings.xml:4621: <string name="autofill_reset_developer_options_complete" msgid="1276741935956594965">"已重置自动填充开发者选项"</string>
res/values-zh-rCN/strings.xml:4652: <string name="graphics_driver_app_preference_prerelease_driver" msgid="7355929161805829480">"开发者驱动程序"</string>
2. 拿其中一个字段名称进行搜索:show_dev_on,查看哪个页面引用了这个字段,从而定位到具体的页面类。
packages/apps/Settings# grep -nr show_dev_on
……
src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java:239: mDevHitToast = Toast.makeText(mContext, R.string.show_dev_on,
3.打开 BuildNumberPreferenceController.java 这个类,查找相关逻辑。有个和Click相关的方法,点进去看看有没有思路:
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
……
// Don't enable developer options until device has been provisioned
if (!WizardManagerHelper.isDeviceProvisioned(mContext)) {
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_SETTINGS_BUILD_NUMBER_PREF);
return false;
}
……
// 有 countdown 计数和 Toast 处理,应该就是处理开发者模式的逻辑了
if (mDevHitCountdown > 0) {
mDevHitCountdown--;
if (mDevHitCountdown == 0 && !mProcessingLastDevHit) {
// Add 1 count back, then start password confirmation flow.
mDevHitCountdown++;
final ChooseLockSettingsHelper helper =
new ChooseLockSettingsHelper(mActivity, mFragment);
mProcessingLastDevHit = helper.launchConfirmationActivity(
REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF,
mContext.getString(R.string.unlock_set_unlock_launch_picker_title));
if (!mProcessingLastDevHit) {
enableDevelopmentSettings();
}
mMetricsFeatureProvider.action(
mMetricsFeatureProvider.getAttribution(mActivity),
MetricsEvent.FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED,
mFragment.getMetricsCategory(),
null,
mProcessingLastDevHit ? 0 : 1);
} else if (mDevHitCountdown > 0
&& mDevHitCountdown < (TAPS_TO_BE_A_DEVELOPER - 2)) {
if (mDevHitToast != null) {
mDevHitToast.cancel();
}
mDevHitToast = Toast.makeText(mContext,
mContext.getResources().getQuantityString(
R.plurals.show_dev_countdown, mDevHitCountdown,
mDevHitCountdown),
Toast.LENGTH_SHORT);
mDevHitToast.show();
}
mMetricsFeatureProvider.action(
mMetricsFeatureProvider.getAttribution(mActivity),
MetricsEvent.FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED,
mFragment.getMetricsCategory(),
null,
0);
} else if (mDevHitCountdown < 0) {
if (mDevHitToast != null) {
mDevHitToast.cancel();
}
mDevHitToast = Toast.makeText(mContext, R.string.show_dev_already,
Toast.LENGTH_LONG);
mDevHitToast.show();
mMetricsFeatureProvider.action(
mMetricsFeatureProvider.getAttribution(mActivity),
MetricsEvent.FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED,
mFragment.getMetricsCategory(),
null,
1);
}
return true;
}
在处理 click 计数前,看到注释中有一句:
// Don't enable developer options until device has been provisioned
即:在设备配置完成之前,不要启用开发者选项
看到 privisioned,马上反应过来原生的一个 Provision 应用,即开机向导。这个应用里做的一件非常重要的事情就是在用户完成配置之后,会设置数据库一个叫做 device_provisioned 的标记位。
4. 查看裁剪列表,确实把Provision这个应用裁剪掉了。查看数据库内的标记位,果然为0,表示设备设置仍未完成:
rk3568:/ # settings get global device_provisioned
0
手动设置一下这个标记位:
rk3568:/ # settings put global device_provisioned 1
重新尝试打开开发者模式,果然成功了。
问题复盘
这次的裁剪主要问题出在 Provision 开机向导上,有点太经验用事了。
之前在做另一个 Soc 预置 Launcher 的时候,替代 Soc 自己的 Launcher 时,在处理解锁环节(系统判断:是否拉起带 bootDirectAware 标记的 Launcher 和 Launcher 优先级)卡了很久,当时的解决方式是引入一个假 Launcher 负责解锁和设置 device_provisioned 标记,替代原生的 Provision 开机向导。
但是RK平台对替换 Launcher 的整体流程做的比较完善,因此不需要自行处理解锁之类的动作,自然就没有引入假 Launcher 这一套。加上我把 Provision 也裁剪掉了,导致没有流程设置 device_provision 的标记,自然引发了这个问题。
特地记录一下这个问题,继续努力。