• 记一次密码控制功能


    需求:控制应用启动,蓝牙开启,USB切MTP模式

    原理:设置里面定义一个PrizeCheckPasswordActivity.java用于验证密码,修改密码,定义一个receiver用于从系统服务中发广播启动Activity.系统服务中不能直接启动PrizeCheckPasswordActivity,否则会报权限问题。

    应用密码控制关键代码:

    1. frameworks/base/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
    2. }
    3. if (interceptHarmfulAppIfNeeded()) {
    4. // If the app has a "harmful app" warning associated with it, we should ask to uninstall
    5. // before issuing the work challenge.
    6. return true;
    7. }
    8. final int app_type = appShouldCheckPasswordOrNot();
    9. if(app_type != -1){
    10. android.util.Log.e("PasswordService","appShouldCheckPasswordOrNot true");
    11. if(interceptShouldCheckPasswordAppIfNeeded(app_type)){
    12. android.util.Log.e("PasswordService","interceptShouldCheckPasswordAppIfNeeded true not start origin app");
    13. return true;
    14. }
    15. }
    16. return interceptLockedManagedProfileIfNeeded();
    17. }
    18. .....
    19. private int appShouldCheckPasswordOrNot(){
    20. final int PASSWORD_ID_HUAWEIMARKET = 4;
    21. final int PASSWORD_ID_BROWSER = 8;
    22. if("com.android.browser".equals(mAInfo.packageName))
    23. return PASSWORD_ID_BROWSER;
    24. if("com.huawei.appmarket".equals(mAInfo.packageName))
    25. return PASSWORD_ID_HUAWEIMARKET;
    26. return -1;
    27. }
    28. private boolean interceptShouldCheckPasswordAppIfNeeded(int type) {
    29. PasswordManager passwordManager = (PasswordManager) mServiceContext
    30. .getSystemService("password");
    31. if(!passwordManager.checkPasswordStatus(type)){
    32. final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
    33. FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
    34. mIntent = new Intent("com.prize.password.action.CHECK_PASSWORD");
    35. mIntent.putExtra("check_type", type);
    36. mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    37. mCallingPid = mRealCallingPid;
    38. mCallingUid = mRealCallingUid;
    39. mResolvedType = null;
    40. mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
    41. mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
    42. return true;
    43. }else{
    44. return false;
    45. }
    46. }

    蓝牙控制:

    1. ./core/java/com/android/server/BluetoothManagerService.java
    2. private final int PASSWORD_ID_BLUETOOTH = 1;
    3. private boolean sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(int type){
    4. int status = android.provider.Settings.Secure.getInt(mContext.getContentResolver(), "status_key", 0);
    5. android.util.Log.i(TAG,"BMS sendPrizeCheckPasswordBroadcastIfPasswordWasWrong status saved =" + status +",type=" + type);
    6. if((type & status) != 0){//password right
    7. return false;
    8. }else{
    9. final String CHECK_PASSWORD_ACTION = "com.prize.password.action.CHECK_PASSWORD_STATUS";
    10. ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.password.PrizeCheckPasswordReceiver");
    11. Intent intent = new Intent();
    12. intent.setComponent(cn);
    13. intent.setAction(CHECK_PASSWORD_ACTION);
    14. intent.putExtra("check_type", type);
    15. mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
    16. return true;
    17. }
    18. }
    19. public boolean enable(String packageName) throws RemoteException {
    20. if(sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(PASSWORD_ID_BLUETOOTH)){
    21. Slog.d(TAG, "PasswordService password is wrong,just return");
    22. return false;
    23. }
    24. if (!checkBluetoothPermissions(packageName, true)) {
    25. if (DBG) {
    26. Slog.d(TAG, "enable(): not enabling - bluetooth disallowed");
    27. }
    28. return false;
    29. }

    USB切MTP模式控制:

    1. ./frameworks/base/services/usb/java/com/android/server/usb/UsbService.java
    2. private final int PASSWORD_ID_USB = 2;
    3. private boolean sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(int type){
    4. int status = android.provider.Settings.Secure.getInt(mContext.getContentResolver(), "status_key", 0);
    5. android.util.Log.i("PasswordService","BMS appShouldinterceptOrNot status saved =" + status +",type=" + type);
    6. if((type & status) != 0){//password right
    7. return false;
    8. }else{
    9. final String CHECK_PASSWORD_ACTION = "com.prize.password.action.CHECK_PASSWORD_STATUS";
    10. ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.password.PrizeCheckPasswordReceiver");
    11. Intent intent = new Intent();
    12. intent.setComponent(cn);
    13. intent.setAction(CHECK_PASSWORD_ACTION);
    14. intent.putExtra("check_type", type);
    15. mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
    16. return true;
    17. }
    18. }
    19. @Override
    20. public void setCurrentFunctions(long functions) {
    21. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
    22. Preconditions.checkArgument(UsbManager.areSettableFunctions(functions));
    23. Preconditions.checkState(mDeviceManager != null);
    24. if(functions == UsbManager.FUNCTION_MTP && sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(PASSWORD_ID_USB)){
    25. android.util.Log.e("PasswordService", "UsbService password is wrong just return");
    26. return;
    27. }
    28. mDeviceManager.setCurrentFunctions(functions);
    29. }

    设置里面的Manifest配置:

    1. <activity
    2. android:name=".password.PrizeCheckPasswordActivity"
    3. android:theme="@style/NoTitleDialog"
    4. android:exported="true">
    5. <intent-filter>
    6. <action android:name="com.prize.password.action.CHECK_PASSWORD" />
    7. <category android:name="android.intent.category.DEFAULT" />
    8. </intent-filter>
    9. </activity>
    10. <receiver
    11. android:name=".password.PrizeCheckPasswordReceiver"
    12. android:exported="true">
    13. <intent-filter>
    14. <action android:name="com.prize.password.action.CHECK_PASSWORD_STATUS" />
    15. </intent-filter>
    16. </receiver>

    dialog样式:

    1. <style name="NoTitleDialog" parent="Theme.AppCompat.Light.Dialog">
    2. <item name="windowNoTitle">trueitem>
    3. <item name="android:windowContentOverlay">@nullitem>
    4. <item name="android:windowIsFloating"> true item>
    5. <item name="android:windowFrame">@nullitem>
    6. <item name="android:backgroundDimEnabled">trueitem>
    7. style>

    注意系统服务发广播的方式,不然由于receiver是在AndroidManifest.xml中静态注册的,很可能会收不到。

  • 相关阅读:
    k8s常用命令
    管理学名词解释
    68-Java的内部类
    webGL开发微信小游戏
    SpringMVC的@InitBinder的作用
    zephyr-os 线程
    Android系统编译优化:使用Ninja加快编译
    报表生成器FastReport .Net用户指南:关于脚本(上)
    RCC目前最近技术与今后发展
    Jmix 中 REST API 的两种实现
  • 原文地址:https://blog.csdn.net/lmpt90/article/details/133826295