需求:控制应用启动,蓝牙开启,USB切MTP模式
原理:设置里面定义一个PrizeCheckPasswordActivity.java用于验证密码,修改密码,定义一个receiver用于从系统服务中发广播启动Activity.系统服务中不能直接启动PrizeCheckPasswordActivity,否则会报权限问题。
应用密码控制关键代码:
- frameworks/base/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
-
- }
- if (interceptHarmfulAppIfNeeded()) {
- // If the app has a "harmful app" warning associated with it, we should ask to uninstall
- // before issuing the work challenge.
- return true;
- }
-
- final int app_type = appShouldCheckPasswordOrNot();
- if(app_type != -1){
- android.util.Log.e("PasswordService","appShouldCheckPasswordOrNot true");
- if(interceptShouldCheckPasswordAppIfNeeded(app_type)){
- android.util.Log.e("PasswordService","interceptShouldCheckPasswordAppIfNeeded true not start origin app");
- return true;
- }
- }
-
- return interceptLockedManagedProfileIfNeeded();
- }
-
- .....
-
-
- private int appShouldCheckPasswordOrNot(){
-
- final int PASSWORD_ID_HUAWEIMARKET = 4;
- final int PASSWORD_ID_BROWSER = 8;
- if("com.android.browser".equals(mAInfo.packageName))
- return PASSWORD_ID_BROWSER;
- if("com.huawei.appmarket".equals(mAInfo.packageName))
- return PASSWORD_ID_HUAWEIMARKET;
-
-
- return -1;
- }
-
- private boolean interceptShouldCheckPasswordAppIfNeeded(int type) {
- PasswordManager passwordManager = (PasswordManager) mServiceContext
- .getSystemService("password");
- if(!passwordManager.checkPasswordStatus(type)){
- final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
- FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
-
- mIntent = new Intent("com.prize.password.action.CHECK_PASSWORD");
- mIntent.putExtra("check_type", type);
- mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- mCallingPid = mRealCallingPid;
- mCallingUid = mRealCallingUid;
- mResolvedType = null;
-
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
- mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
- return true;
- }else{
- return false;
- }
- }
蓝牙控制:
- ./core/java/com/android/server/BluetoothManagerService.java
-
- private final int PASSWORD_ID_BLUETOOTH = 1;
- private boolean sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(int type){
- int status = android.provider.Settings.Secure.getInt(mContext.getContentResolver(), "status_key", 0);
- android.util.Log.i(TAG,"BMS sendPrizeCheckPasswordBroadcastIfPasswordWasWrong status saved =" + status +",type=" + type);
- if((type & status) != 0){//password right
- return false;
- }else{
- final String CHECK_PASSWORD_ACTION = "com.prize.password.action.CHECK_PASSWORD_STATUS";
- ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.password.PrizeCheckPasswordReceiver");
- Intent intent = new Intent();
- intent.setComponent(cn);
- intent.setAction(CHECK_PASSWORD_ACTION);
- intent.putExtra("check_type", type);
- mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
- return true;
- }
- }
-
- public boolean enable(String packageName) throws RemoteException {
- if(sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(PASSWORD_ID_BLUETOOTH)){
- Slog.d(TAG, "PasswordService password is wrong,just return");
- return false;
- }
-
- if (!checkBluetoothPermissions(packageName, true)) {
- if (DBG) {
- Slog.d(TAG, "enable(): not enabling - bluetooth disallowed");
- }
- return false;
- }
USB切MTP模式控制:
- ./frameworks/base/services/usb/java/com/android/server/usb/UsbService.java
-
- private final int PASSWORD_ID_USB = 2;
- private boolean sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(int type){
- int status = android.provider.Settings.Secure.getInt(mContext.getContentResolver(), "status_key", 0);
- android.util.Log.i("PasswordService","BMS appShouldinterceptOrNot status saved =" + status +",type=" + type);
- if((type & status) != 0){//password right
- return false;
- }else{
- final String CHECK_PASSWORD_ACTION = "com.prize.password.action.CHECK_PASSWORD_STATUS";
- ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.password.PrizeCheckPasswordReceiver");
- Intent intent = new Intent();
- intent.setComponent(cn);
- intent.setAction(CHECK_PASSWORD_ACTION);
- intent.putExtra("check_type", type);
- mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
- return true;
- }
- }
- @Override
- public void setCurrentFunctions(long functions) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- Preconditions.checkArgument(UsbManager.areSettableFunctions(functions));
- Preconditions.checkState(mDeviceManager != null);
- if(functions == UsbManager.FUNCTION_MTP && sendPrizeCheckPasswordBroadcastIfPasswordWasWrong(PASSWORD_ID_USB)){
- android.util.Log.e("PasswordService", "UsbService password is wrong just return");
- return;
- }
- mDeviceManager.setCurrentFunctions(functions);
- }
设置里面的Manifest配置:
- <activity
- android:name=".password.PrizeCheckPasswordActivity"
- android:theme="@style/NoTitleDialog"
- android:exported="true">
- <intent-filter>
- <action android:name="com.prize.password.action.CHECK_PASSWORD" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
-
- </activity>
-
- <receiver
- android:name=".password.PrizeCheckPasswordReceiver"
- android:exported="true">
- <intent-filter>
- <action android:name="com.prize.password.action.CHECK_PASSWORD_STATUS" />
- </intent-filter>
- </receiver>
dialog样式:
- <style name="NoTitleDialog" parent="Theme.AppCompat.Light.Dialog">
-
- <item name="windowNoTitle">trueitem>
-
- <item name="android:windowContentOverlay">@nullitem>
-
- <item name="android:windowIsFloating"> true item>
-
- <item name="android:windowFrame">@nullitem>
-
- <item name="android:backgroundDimEnabled">trueitem>
- style>
注意系统服务发广播的方式,不然由于receiver是在AndroidManifest.xml中静态注册的,很可能会收不到。