MIUI12_Global未知来源安装等待时间patcher

快过年了,被疫情困在家,实在无聊就给小米9换了个MIUI12_Global 的ROM。但是,每次开启USB调试,以及允许安装应用都需要等待5秒才能授权。于是楼主花费了几个钟头的时间终于搞定了五秒的等待时间,虽然只测试了小米9的V12.0.4.0.QFAMIXM,但是其他机型或者其他版本的ROM应该都差不多,感兴趣的可以测试一下。

机型 小米9(cepheus)
ROM V12.0.4.0.QFAMIXM_20210115.0000.00_10.0_global
相关软件 设置(/system/product/priv-app/Settings/Settings.apk)
手机管家(/system/priv-app/SecurityCenter/SecurityCenter.apk)

 

 

 

 

 

1、定位软件:当前进程(名字就叫当前进程)

我在芥子空间找到了app【当前进程】用来查看当前窗口Activity的软件。

首先打开软件,然后开启悬浮窗进行记录Activity活动,

MIUI12_Global未知来源安装等待时间patcher

MIUI12_Global未知来源安装等待时间patcherMIUI12_Global未知来源安装等待时间patcher

 

一看这个Activity的名字立马感觉就来了。

二话不说,把SecurityCenter.apk拿出用jd-gui来看看。

2、分析

找到com.miui.permcenter.privacymanager.SpecialPermissionInterceptActivity 

有第一张图我们可以看到这个Activity的界面有两个Button,而且其中Button(Text="允许")需要计时结束后,才可点击,但是Button(Text="取消")则是随时可点击的。

用jd-gui打开com.miui.permcenter.privacymanager.SpecialPermissionInterceptActivity的源码:

package com.miui.permcenter.privacymanager;

import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import b.b.f.j.B;
import b.b.f.j.F;
import b.b.f.j.o;
import com.miui.permcenter.compact.SystemPropertiesCompat;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import miui.app.Activity;

public class SpecialPermissionInterceptActivity extends Activity implements View.OnClickListener {
  private static final Map<String, b> a = new HashMap<String, b>();
  
  private a b;
  
  private String c;
  
  private String d;
  
  private String e;
  
  private TextView f;
  
  private LinearLayout g;
  
  private TextView h;
  
  private Button i;
  
  private Button j;
  
  private int k;
  
  static {
    a.put("perm_install_unknown", new b(2131757339, 2130903079, 2131757335));
    a.put("perm_notification", new b(2131757336, 2130903077, 2131757337));
    a.put("perm_app_statistics", new b(2131757338, 2130903078, 2131757337));
    a.put("miui_open_debug", new b(2131755938, 2130903055, 2131755937));
    a.put("miui_close_optimization", new b(2131757023, 2130903063, 2131757022));
    a.put("oaid_close", new b(0, 2131757158, 2131757159));
  }
  
  private void a() {
    try {
      Window window = getWindow();
      window.addFlags(-2147483648);
      window.getDecorView().setSystemUiVisibility(768);
      window.getClass().getMethod("setNavigationBarColor", new Class[] { int.class }).invoke(window, new Object[] { Integer.valueOf(0) });
    } catch (Exception exception) {}
  }
  
  private void a(boolean paramBoolean) {
    if ("miui_open_debug".equals(this.d) && paramBoolean) {    
      Settings.Global.putInt(getContentResolver(), "adb_enabled", paramBoolean);
    } else if ("miui_close_optimization".equals(this.d) && paramBoolean) {
      SystemPropertiesCompat.set("persist.sys.miui_optimization", Boolean.valueOf(paramBoolean ^ true).toString());
    } 
    if (paramBoolean) {
      byte b = -1;
    } else {
      paramBoolean = false;
    } 
    setResult(paramBoolean);    //设置Activity的Result,现在还用不到,但是在分析设置的时候很有用
    finish();
  }
  
  private void b() {
//这个方法就是对这个Activity窗口不同的权限请求的判断
    String[] arrayOfString;
    if (this.d.startsWith("perm") && !TextUtils.isEmpty(this.e)) {//判断是要打开usb还是未知来源的安装请求。
      this.f.setText(getString(((b)a.get(this.d)).a, new Object[] { B.j((Context)this, this.c) }));
      this.h.setText(getString(((b)a.get(this.d)).c, new Object[] { this.e }));
    } else if (this.d.startsWith("miui")) {
      this.f.setText(((b)a.get(this.d)).a);
      this.h.setText(((b)a.get(this.d)).c);
    } 
    if ("oaid_close".equals(this.d)) {
      this.f.setVisibility(4);
      this.h.setText(((b)a.get(this.d)).c);
      arrayOfString = new String[1];
      arrayOfString[0] = getString(((b)a.get(this.d)).b);
    } else {
      arrayOfString = getResources().getStringArray(((b)a.get(this.d)).b);
    } 
    LayoutInflater layoutInflater = LayoutInflater.from((Context)this);
    int i = arrayOfString.length;
    for (byte b = 0; b < i; b++) {
      String str = arrayOfString[b];
      View view = layoutInflater.inflate(2131493425, (ViewGroup)this.g, false);
      TextView textView = (TextView)view.findViewById(2131297085);
      if (arrayOfString.length == 1) {
        view.findViewById(2131297086).setVisibility(8);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(textView.getLayoutParams());
        layoutParams.leftMargin = 0;
        textView.setLayoutParams((ViewGroup.LayoutParams)layoutParams);
      } 
      textView.setText(str);
      this.g.addView(view);
    } 
    this.i.setText(getString(2131755748, new Object[] { Integer.valueOf(this.k) }));
    this.b.sendEmptyMessageDelayed(1, 1000L);
  }
  
  private void c() {
    int i = --this.k;        //前面已经将k设为5,这里对k的值进行递减
    if (i <= 0) {            //判断是否小于0,如果小于0,则this.i.setEnabled(true);
      this.i.setText(2131755747);
      this.i.setEnabled(true);    //允许 按键被设为可点击。
      this.k = 0;
    } else {
      this.i.setText(getString(2131755748, new Object[] { Integer.valueOf(i) }));
      this.b.removeMessages(1);
      this.b.sendEmptyMessageDelayed(1, 1000L);    // 时间为1秒
    } 
  }
  
  public void onBackPressed() {}
  
  public void onClick(View paramView) {     
  //这个方法就是两个按钮共同绑定的方法,用户带年纪允许或者取消都会调用这个方法
    boolean bool;
    int i = paramView.getId();
    if (i != 2131297087) { //判断i来确定用户点击了允许还是取消,并且将bool赋值(允许true)                                  
      if (i != 2131297091)    //查找一下id可以找到相关信息,这里就跳过了
        return;               
      bool = false;
    } else {
      bool = true;
    } 
    a(bool);                  //当用户点击允许,这调用a(bool),这里的bool为true;
  }
  
  protected void onCreate(Bundle paramBundle) {    // 1.先看这个方法
    super.onCreate(paramBundle);
    Window window = getWindow();
    window.setBackgroundDrawable((Drawable)new ColorDrawable(getResources().getColor(2131100554)));
    window.setLayout(-1, -1);
    window.addFlags(4);
    setContentView(2131493424);
    a();
    this.c = getIntent().getStringExtra("pkgName");
    this.d = getIntent().getStringExtra("permName");
    this.e = getIntent().getStringExtra("permDesc");
    if (!a.containsKey(this.d)) {
      finish();
      return;
    } 
    if (paramBundle != null) {
      this.k = paramBundle.getInt("KET_STEP_COUNT", 5);    //可以合理的怀疑一下k是不是那5秒
    } else {
      this.k = 5;
    } 
    this.b = new a(this);
    this.f = (TextView)findViewById(2131297090);
    this.g = (LinearLayout)findViewById(2131297088);
    this.h = (TextView)findViewById(2131297089);
    this.i = (Button)findViewById(2131297087);//这里的this.i和this.j其实就是两个Button组件
        
    this.j = (Button)findViewById(2131297091);
    this.i.setEnabled(false);//这里按钮i被设置为不可点击状态,可以断定这个就是“取消”按钮
        
    this.i.setOnClickListener(this); //两个按钮绑定了同一个OnClick
    this.j.setOnClickListener(this);
       
    if (F.a()) {
      o.b((View)this.i);
      o.b((View)this.j);
    } 
    b();//跟进看一下
  }
  
  protected void onDestroy() {
    super.onDestroy();
    a a1 = this.b;
    if (a1 != null)
      a1.removeMessages(1); 
  }
  
  protected void onNewIntent(Intent paramIntent) {
    super.onNewIntent(paramIntent);
  }
  
  protected void onSaveInstanceState(Bundle paramBundle) {
    super.onSaveInstanceState(paramBundle);
    paramBundle.putInt("KET_STEP_COUNT", this.k);
  }
  
  private static class a extends Handler {
    private WeakReference<SpecialPermissionInterceptActivity> a;
    
    public a(SpecialPermissionInterceptActivity param1SpecialPermissionInterceptActivity) {
      this.a = new WeakReference<SpecialPermissionInterceptActivity>(param1SpecialPermissionInterceptActivity);
    }
    
    public void handleMessage(Message param1Message) {
      super.handleMessage(param1Message);
      SpecialPermissionInterceptActivity specialPermissionInterceptActivity = this.a.get();
      if (specialPermissionInterceptActivity != null && !specialPermissionInterceptActivity.isFinishing() && !specialPermissionInterceptActivity.isDestroyed())
        SpecialPermissionInterceptActivity.a(specialPermissionInterceptActivity); 
    }
  }
  
  public static class b {
    int a;
    
    int b;
    
    int c;
    
    public b(int param1Int1, int param1Int2, int param1Int3) {
      this.a = param1Int1;
      this.b = param1Int2;
      this.c = param1Int3;
    }
  }
}

分析到这里,想要去掉这5秒以及是手到擒来的事了。我们可以把k的值在onCreate方法中变成负数,或者将Button i 设置为setEnabled(true);即让它直接可以点击。

。。。。。。。

如果仅仅在SpecialPermissionInterceptActivity中修改它的组件属性就任然会有第一张图示的提示消息。楼主进一步琢磨着,准备向魔爪伸向Settings.apk。

当前进程App 可以看到

 

               MIUI12_Global未知来源安装等待时间patcher             MIUI12_Global未知来源安装等待时间patcher            MIUI12_Global未知来源安装等待时间patcher

当用户进入这个界面(com.android,settings.Settings$ManageAppExternalSourcesActivity),点击“允许来自此来源的应用”   就会启动com.miui.permcenter.privacymanager.SpecialPermissionInterceptActivity

所以在Settings.apk(包名:com.android,settings),启动SecurityCenter.apk(包名:com.miui.securitycenter)

我们可以在Settings.apk来查找相关的源码,查找是否有与com.miui.securitycenter相关的startActivity()方法。

经过人肉筛选,我定位到

com.android.settings.applications.appinfo.ExternalSourcesDetails

发现ExternalSourcesDetails类中有个fV()方法会启动com.miui.securitycenter的Activity

Intent intent = new Intent("com.miui.securitycenter.action.UNKNOWN_SOURCE_VERIFY");
intent.setPackage("com.miui.securitycenter");
startActivityForResult(intent, 101);

所以当fV()被调用,向com.miui.securitycenter发送intent,然后就会弹出SpecialPermissionInterceptActivity重要警告的窗口,

这里面有个十分关键的方法:

onPreferenceChange() 返回boolean值

这个方法就是当我们点击按钮后响应的方法,它的返回值决定了按钮是否改变。(return false 不改变按钮状态,return true 则将按钮改为相反的状态)

当我们点击“允许来自此来源的应用”就会弹出SpecialPermissionInterceptActivity重要警告的窗口,所以我们对onPreferenceChange()进行分析:

  public boolean onPreferenceChange(Preference paramPreference, Object paramObject) {
    boolean bool = ((Boolean)paramObject).booleanValue();
    if (paramPreference == this.Ps) {
      AppStateInstallAppsBridge.InstallAppsState installAppsState = this.Ws;
      if (installAppsState != null && bool != installAppsState.gx()) {
        if (bool) {
          Intent intent = a.c(((AppInfoBase)this).mPackageName, "perm_install_unknown", this.mContext.getResources().getString(2131889241));
          if (a.g(this.mContext, intent)) {
            We(102);
            return true;
          } 
          if (fV())
            return true; 
        } 
        We(bool);
      } 
      return true;
    } 
    return false;
  }
 

我们看这个bool 的值实际上就是onPreferenceChange()第二个实际参数强制转换成的boolean值,

(1)如果bool = true;则会调用fV()启动警告窗口,改变按钮状态

(2)如果bool = false;则会执行We(bool);再看一下

onPreferenceChange()中调用了fV()方法,如果返回真值,就改变按钮状态。然后将bool作为参数执行We()方法

  private void We(boolean paramBoolean) {
    if (Settings.ManageAppExternalSourcesActivity.class.getName().equals(getIntent().getComponent().getClassName())) {
      boolean bool;
      if (paramBoolean) {
        bool = true;
      } else {
        bool = false;
      } 
      setResult(bool);
    } 
    setCanInstallApps(paramBoolean);
    refreshUi();
  }

其实很容易看出来,实际上

We(boolean paramBoolean)方法的参数传递给setCanInstallApps()方法。

然后未知来源的安装权限就到手了。

我们可以在onPreferenceChange()方法中将调用fV()方法的代码注释掉,换成执行We(true)的代码就可以完成修改了。

package com.android.settings.applications.appinfo;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import androidx.preference.Preference;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.Settings;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppInfoWithHeader;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.applications.ApplicationsState;
import d.a.a.a;
import miui.os.Build;

public class ExternalSourcesDetails extends AppInfoWithHeader implements Preference.b {
  private RestrictedSwitchPreference Ps;
  
  private AppStateInstallAppsBridge Vs;
  
  private AppStateInstallAppsBridge.InstallAppsState Ws;
  
  private ActivityManager mActivityManager;
  
  private AppOpsManager mAppOpsManager;
  
  private Context mContext;
  
  private UserManager mUserManager;
  
  private void Ii(int paramInt) {
    if (UserHandle.isCore(paramInt))
      return; 
    this.mActivityManager.killUid(paramInt, "User denied OP_REQUEST_INSTALL_PACKAGES");
  }
  
  private void We(boolean paramBoolean) {
    if (Settings.ManageAppExternalSourcesActivity.class.getName().equals(getIntent().getComponent().getClassName())) {
      boolean bool;
      if (paramBoolean) {
        bool = true;
      } else {
        bool = false;
      } 
      setResult(bool);
    } 
    setCanInstallApps(paramBoolean);
    refreshUi();
  }
  
  public static CharSequence b(Context paramContext, ApplicationsState.a parama) {
    UserHandle userHandle = UserHandle.getUserHandleForUid(parama.info.uid);
    UserManager userManager = UserManager.get(paramContext);
    int i = userManager.getUserRestrictionSource("no_install_unknown_sources", userHandle);
    i = userManager.getUserRestrictionSource("no_install_unknown_sources_globally", userHandle) | i;
    if ((i & 0x1) != 0)
      return paramContext.getString(2131888227); 
    if (i != 0)
      return paramContext.getString(2131888224); 
    if ((new AppStateInstallAppsBridge(paramContext, null, null)).s(parama.info.packageName, parama.info.uid).gx()) {
      i = 2131886579;
    } else {
      i = 2131886580;
    } 
    return paramContext.getString(i);
  }
  
  private boolean fV() {
    if (!Build.IS_INTERNATIONAL_BUILD && !Build.IS_TABLET && UserHandle.myUserId() == 0) {
      Intent intent = new Intent("com.miui.securitycenter.action.UNKNOWN_SOURCE_VERIFY");
      intent.setPackage("com.miui.securitycenter");
      startActivityForResult(intent, 101);
      return true;
    } 
    return false;
  }
  
  public int ab() {
    return 808;
  }
  
  protected AlertDialog k(int paramInt1, int paramInt2) {
    return null;
  }
  
  public void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent) {
    super.onActivityResult(paramInt1, paramInt2, paramIntent);
    boolean bool1 = false;
    boolean bool2 = false;
    if (paramInt1 == 101) {
      if (paramInt2 == -1)
        bool2 = true; 
      We(bool2);
    } else if (paramInt1 == 102) {
      bool2 = bool1;
      if (paramInt2 == -1)
        bool2 = true; 
      AppStateInstallAppsBridge.InstallAppsState installAppsState = this.Ws;
      if (installAppsState != null && bool2 != installAppsState.gx()) {
        if (bool2 && fV())
          return; 
        We(true);
      } 
    } 
  }
  
  public void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    Activity activity = getActivity();
    this.Vs = new AppStateInstallAppsBridge((Context)activity, ((AppInfoBase)this).mState, null);
    this.mAppOpsManager = (AppOpsManager)activity.getSystemService("appops");
    this.mActivityManager = (ActivityManager)activity.getSystemService(ActivityManager.class);
    this.mUserManager = UserManager.get((Context)activity);
    addPreferencesFromResource(2132082829);
    this.Ps = (RestrictedSwitchPreference)findPreference("external_sources_settings_switch");
    this.Ps.setOnPreferenceChangeListener(this);
    this.mContext = (Context)activity;
  }
  
  public void onDestroy() {
    this.Vs.release();
    super.onDestroy();
  }
  
  public boolean onPreferenceChange(Preference paramPreference, Object paramObject) {
    boolean bool = ((Boolean)paramObject).booleanValue();
    if (paramPreference == this.Ps) {
      AppStateInstallAppsBridge.InstallAppsState installAppsState = this.Ws;
      if (installAppsState != null && bool != installAppsState.gx()) {
        if (bool) {
          Intent intent = a.c(((AppInfoBase)this).mPackageName, "perm_install_unknown", this.mContext.getResources().getString(2131889241));
          if (a.g(this.mContext, intent)) {
            We(102);
            return true;
          } 
          if (fV())
            return true; 
        } 
        We(bool);
      } 
      return true;
    } 
    return false;
  }
  
  protected boolean refreshUi() {
    PackageInfo packageInfo = ((AppInfoBase)this).mPackageInfo;
    if (packageInfo == null || packageInfo.applicationInfo == null)
      return false; 
    if (this.mUserManager.hasBaseUserRestriction("no_install_unknown_sources", UserHandle.of(UserHandle.myUserId()))) {
      this.Ps.setChecked(false);
      this.Ps.setSummary(2131888224);
      this.Ps.setEnabled(false);
      return true;
    } 
    this.Ps.Ba("no_install_unknown_sources");
    if (!this.Ps.zj())
      this.Ps.Ba("no_install_unknown_sources_globally"); 
    if (this.Ps.zj())
      return true; 
    this.Ws = this.Vs.s(((AppInfoBase)this).mPackageName, ((AppInfoBase)this).mPackageInfo.applicationInfo.uid);
    if (!this.Ws.isPotentialAppSource()) {
      this.Ps.setEnabled(false);
      return true;
    } 
    this.Ps.setChecked(this.Ws.gx());
    return true;
  }
  
  @VisibleForTesting
  void setCanInstallApps(boolean paramBoolean) {
    byte b1;
    AppOpsManager appOpsManager = this.mAppOpsManager;
    int i = ((AppInfoBase)this).mPackageInfo.applicationInfo.uid;
    String str = ((AppInfoBase)this).mPackageName;
    if (paramBoolean) {
      b1 = 0;
    } else {
      b1 = 2;
    } 
    appOpsManager.setMode(66, i, str, b1);
    if (!paramBoolean)
      Ii(((AppInfoBase)this).mPackageInfo.applicationInfo.uid); 
  }
}

 

ps:关于如何定位到代码,就自己慢慢琢磨吧,这是很难解释清楚的。

 

 

 

 

 

上一篇:android开发获取手机当前界面Activity完整包名的解决方法


下一篇:小米miui查看连接过已保存的密码方法