上回我们说到如何干掉 adb install 时候的框,最近又被oppo的操作气到了,插上 usb 非要点一下框才能连 adb,非常恼火。今天把这个烦人的框给干掉。
代码链接:https://gist.github.com/LeadroyaL/e271ca18f213f058b8e310654cae310d
### 背景
用 oppo 的开发者都知道,无论如何设置,插上 USB 后,一定要主动点击 【传输文件】 这个按钮,否则 adb 连不上。每次插 USB 都要点一下,非常让人恼火,于是写个 xposed 插件把这个东西给干掉。
目标:每次连接 USB 后,让 usb 调试可以自动开启。
### 确认位置
使用 monitor dump ui,发现在 com.android.systemui 下。
直接用 apktool 解包时提醒缺少资源,需要用 apktool if 安装 framework 的资源,然后再解包。
1 2 3 4 5 |
adb pull /system/framework/oppo-framework-res.apk adb pull /system/framework/framework-res.apk apktool if oppo-framework-res.apk apktool if framework-res.apk apktool d SystemUI.apk |
grep 字符串,确认到 UsbService 文件
1 2 3 4 5 6 7 8 9 10 |
➜ SystemUI grep "用于" * -R res/values-zh-rCN/strings.xml: <string name="usb_usage_purpose">USB 用于</string> ➜ SystemUI grep "usb_usage_purpose" * -R res/values/public.xml: <public type="string" name="usb_usage_purpose" id="0x7f1108b1" /> res/values/strings.xml: <string name="usb_usage_purpose">Use USB to</string> ➜ SystemUI grep 0x7f1108b1 * -R res/values/public.xml: <public type="string" name="usb_usage_purpose" id="0x7f1108b1" /> smali_classes2/com/coloros/systemui/notification/usb/UsbService.smali: const v2, 0x7f1108b1 |
### 分析代码
看到 showUsbDialog
方法有明显的绘制 GUI 的行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
private void showUsbDialog(boolean arg8) { .......... Builder v1 = new Builder(this, 0x7F1202B3).setDialogType(0).setTitle(0x7F1108B1); // style:Theme.ColorSupport.Dialog.Alert.UsbType UsbTypeSelectAdapter v2 = this.mUsbTypeAdapter; com.coloros.systemui.notification.usb.UsbService.5 v3 = Utils.isOptionDisabled(this.mContext) ? null : new DialogInterface.OnClickListener() { @Override // android.content.DialogInterface$OnClickListener public void onClick(DialogInterface arg2, int arg3) { UsbService.this.mUsbTypeAdapter.setChecked(arg3); UsbService.this.onUsbSelect(arg3); UsbService.this.delayDismiss(); if(arg8) { UsbStatistics.getInstance().collectUsbNotificationClickStatistic(UsbService.this.mContext, v0, arg3); return; } UsbStatistics.getInstance().collectUsbInsertStatistic(UsbService.this.mContext, arg3); } }; this.mUsbSelectDialog = v1.setSingleChoiceItems(v2, 0, v3).create(); this.mUsbTypeAdapter.setRadioClickListener(new RadioButtonClickListener() { @Override // com.coloros.systemui.notification.usb.UsbTypeSelectAdapter$RadioButtonClickListener public void onRadioButtonClick(int arg2) { UsbService.this.onUsbSelect(arg2); UsbService.this.delayDismiss(); } }); ....... } |
使用 xposed 进行 hook,打印一下栈回溯
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
java.lang.RuntimeException at de.robv.android.xposed.XC_MethodHook.callBeforeHookedMethod(XC_MethodHook.java:51) at EdHooker_.hook(Unknown Source:96) at com.coloros.systemui.notification.usb.UsbService.updateUsbNotification(UsbService.java:706) at com.coloros.systemui.notification.usb.UsbService.onUsbConnected(UsbService.java:595) at com.coloros.systemui.notification.usb.UsbService.access$1500(UsbService.java:71) at com.coloros.systemui.notification.usb.UsbService$4.run(UsbService.java:554) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:238) at android.app.ActivityThread.main(ActivityThread.java:7767) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1016) |
发现插入 usb 的一瞬间触发的是 onUsbConnected
。
观察代码,发现处理 com.oppo.test.only.charge 时会关掉 adb 调试,于是我们对这个 receiver 进行过滤。尝试后发现没有效果。
试一试将 onUsbConnected
replace 为空实现。尝试后发现满足我们的要求,插上后就有adb了,但是通知栏的修改USB用途的Notification没有被显示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
private void onUsbConnected(Context arg4) { if(SystemProperties.get("ro.oppo.factory_mode", "0").equals("1")) { return; } int v0 = 0; if(NotificationFeatureOption.isCtaSupport()) { v0 = 2; } Settings.System.putInt(this.mContext.getContentResolver(), "usb_remeber_selection", v0); this.updateAdbNotification(arg4); this.updateUsbNotification(arg4, v0); if((this.needReset()) && !this.mOpm.isClosedSuperFirewall()) { this.changeUsbConfig(arg4, v0); } |
阅读代码发现,需要replace时调用 updateUsbNotification
来更新通知栏,传参给 1,表示正在传输文件。
尝试后完全满足我们的要求,框也不弹了,adb 也不断了,调试起来更有劲了,收工!
### 成品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class Entry implements IXposedHookLoadPackage { @Override public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { ClassLoader classLoader = lpparam.classLoader; if (lpparam.packageName.equals("com.android.systemui")) { XposedBridge.log("Patch oppo usb dialog START"); XposedHelpers.findAndHookMethod("com.coloros.systemui.notification.usb.UsbService", classLoader, "onUsbConnected", Context.class, new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { Object thiz = param.thisObject; thiz.getClass().getMethod("updateAdbNotification", Context.class).invoke(thiz, (Context) param.args[0]); thiz.getClass().getField("sNeedShowUsbDialog").set(null, false); thiz.getClass().getMethod("updateUsbNotification", Context.class, int.class).invoke(thiz, (Context) param.args[0], 1); return null; } }); XposedBridge.log("Patch oppo usb dialog END"); } } } |