安卓跳过授权弹窗直接授权


安卓跳过授权弹窗直接授权

方法一:把运行时授权改成安装时授权

  • 在PermissionManagerService.java中修改restorePermissionState()方法
if (bp.isNormal()) {
    // For all apps normal permissions are install time ones.
    grant = GRANT_INSTALL;
} else if (bp.isRuntime()) {
    if (origPermissions.hasInstallPermission(bp.getName())
        || upgradedActivityRecognitionPermission != null) {
        // Before Q we represented some runtime permissions as install permissions,
        // in Q we cannot do this anymore. Hence upgrade them all.
        grant = GRANT_UPGRADE;
    } else {
        // For modern apps keep runtime permissions unchanged.
        if(checkPermissionWhiteList(pkg.packageName)){
            // 把运行时授权改成安装时授权,程序安装时就授权,就不会再有弹窗了
            grant = GRANT_INSTALL;
        }else{
            grant = GRANT_RUNTIME;
        }
    }
} else if (bp.isSignature()) {
    // For all apps signature permissions are install time ones.
    allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
    if (allowedSig) {
        grant = GRANT_INSTALL;
    }
}

方法二:拦截弹窗并直接授权

  • 修改GrantPermissionsActivity.java
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.packageinstaller.permission.ui;

import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

import static com.android.packageinstaller.PermissionControllerStatsLog.GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE;
import static com.android.packageinstaller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED;
import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler.DENIED;
import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler.DENIED_DO_NOT_ASK_AGAIN;
import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler.GRANTED_ALWAYS;
import static com.android.packageinstaller.permission.ui.GrantPermissionsViewHandler.GRANTED_FOREGROUND_ONLY;
import static com.android.packageinstaller.permission.utils.Utils.getRequestMessage;

import android.app.Activity;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.text.Html;
import android.text.Spanned;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.packageinstaller.DeviceUtils;
import com.android.packageinstaller.PermissionControllerStatsLog;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissions;
import com.android.packageinstaller.permission.model.Permission;
import com.android.packageinstaller.permission.ui.auto.GrantPermissionsAutoViewHandler;
import com.android.packageinstaller.permission.utils.ArrayUtils;
import com.android.packageinstaller.permission.utils.PackageRemovalMonitor;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.permissioncontroller.R;

/// M: CTA requirement - permission control @{
import android.os.UserHandle;
import android.content.pm.PermissionInfo;
import java.util.LinkedHashMap;
import com.android.packageinstaller.permission.model.PermissionState;
import com.android.packageinstaller.permission.utils.Utils;
///@}

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;

public class GrantPermissionsActivity extends Activity
        implements GrantPermissionsViewHandler.ResultListener {

    private static final String LOG_TAG = "GrantPermissionsActivity";

    private static final String KEY_REQUEST_ID = GrantPermissionsActivity.class.getName()
            + "_REQUEST_ID";

    public static int NUM_BUTTONS = 5;
    public static int LABEL_ALLOW_BUTTON = 0;
    public static int LABEL_ALLOW_ALWAYS_BUTTON = 1;
    public static int LABEL_ALLOW_FOREGROUND_BUTTON = 2;
    public static int LABEL_DENY_BUTTON = 3;
    public static int LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON = 4;

    /** Unique Id of a request */
    private long mRequestId;

    private String[] mRequestedPermissions;
    private CharSequence[] mButtonLabels;

    private ArrayMap, GroupState> mRequestGrantPermissionGroups =
            new ArrayMap<>();

    private GrantPermissionsViewHandler mViewHandler;
    private AppPermissions mAppPermissions;

    boolean mResultSet;

    /**
     * Listens for changes to the permission of the app the permissions are currently getting
     * granted to. {@code null} when unregistered.
     */
    private @Nullable PackageManager.OnPermissionsChangedListener mPermissionChangeListener;

    /**
     * Listens for changes to the app the permissions are currently getting granted to. {@code null}
     * when unregistered.
     */
    private @Nullable PackageRemovalMonitor mPackageRemovalMonitor;

    /** Package that requested the permission grant */
    private String mCallingPackage;
    /** uid of {@link #mCallingPackage} */
    private int mCallingUid;

    private int getPermissionPolicy() {
        DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
        return devicePolicyManager.getPermissionPolicy(null);
    }

    /**
     * Try to add a single permission that is requested to be granted.
     *
     * 

This does not expand the permissions into the {@link #computeAffectedPermissions * affected permissions}. * * @param group The group the permission belongs to (might be a background permission group) * @param permName The name of the permission to add * @param isFirstInstance Is this the first time the groupStates get created */ private void addRequestedPermissions(AppPermissionGroup group, String permName, boolean isFirstInstance) { Log.e("temptag", "权限组" + group.getName() + "加入新权限" + permName); if (!group.isGrantingAllowed()) { reportRequestResult(permName, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED); // Skip showing groups that we know cannot be granted. return; } Permission permission = group.getPermission(permName); // If the permission is restricted it does not show in the UI and // is not added to the group at all, so check that first. if (permission == null && ArrayUtils.contains( mAppPermissions.getPackageInfo().requestedPermissions, permName)) { reportRequestResult(permName, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION); return; // We allow the user to choose only non-fixed permissions. A permission // is fixed either by device policy or the user denying with prejudice. } else if (group.isUserFixed()) { reportRequestResult(permName, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED); return; } else if (group.isPolicyFixed() && !group.areRuntimePermissionsGranted() || permission.isPolicyFixed()) { reportRequestResult(permName, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED); return; } Pair groupKey = new Pair<>(group.getName(), group.isBackgroundGroup()); GroupState state = mRequestGrantPermissionGroups.get(groupKey); if (state == null) { state = new GroupState(group); Log.e("temptag", "新加groupstate=" + Arrays.toString(state.affectedPermissions)); mRequestGrantPermissionGroups.put(groupKey, state); }else{ Log.e("temptag", "groupstate已经存在" + Arrays.toString(state.affectedPermissions)); } state.affectedPermissions = ArrayUtils.appendString( state.affectedPermissions, permName); boolean skipGroup = false; switch (getPermissionPolicy()) { case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: { final String[] filterPermissions = new String[]{permName}; group.grantRuntimePermissions(false, filterPermissions); group.setPolicyFixed(filterPermissions); state.mState = GroupState.STATE_ALLOWED; skipGroup = true; reportRequestResult(permName, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED); } break; case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: { final String[] filterPermissions = new String[]{permName}; group.setPolicyFixed(filterPermissions); state.mState = GroupState.STATE_DENIED; skipGroup = true; reportRequestResult(permName, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED); } break; default: { if (group.areRuntimePermissionsGranted()) { group.grantRuntimePermissions(false, new String[]{permName}); state.mState = GroupState.STATE_ALLOWED; skipGroup = true; reportRequestResult(permName, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED); } } break; } if (skipGroup && isFirstInstance) { // Only allow to skip groups when this is the first time the dialog was created. // Otherwise the number of groups changes between instances of the dialog. state.mState = GroupState.STATE_SKIPPED; } } /** * Report the result of a grant of a permission. * * @param permission The permission that was granted or denied * @param result The permission grant result */ private void reportRequestResult(@NonNull String permission, int result) { boolean isImplicit = !ArrayUtils.contains(mRequestedPermissions, permission); Log.v(LOG_TAG, "Permission grant result requestId=" + mRequestId + " callingUid=" + mCallingUid + " callingPackage=" + mCallingPackage + " permission=" + permission + " isImplicit=" + isImplicit + " result=" + result); PermissionControllerStatsLog.write( PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED, mRequestId, mCallingUid, mCallingPackage, permission, isImplicit, result); } /** * Report the result of a grant of a permission. * * @param permissions The permissions that were granted or denied * @param result The permission grant result */ private void reportRequestResult(@NonNull String[] permissions, int result) { for (String permission : permissions) { reportRequestResult(permission, result); } } private boolean checkPermissionWhiteList(String pkgName) { if (pkgName == null || "".equals(pkgName)) return false; List whiteList = new ArrayList<>(); whiteList.add("包名"); whiteList.add("包名"); for (String s : whiteList) { if (s.equals(pkgName)) return true; } return false; } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); if (icicle == null) { mRequestId = new Random().nextLong(); } else { mRequestId = icicle.getLong(KEY_REQUEST_ID); } getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); // Cache this as this can only read on onCreate, not later. mCallingPackage = getCallingPackage(); SafetyNetLogger.logIfHasUndefinedPermissionGroup(getPackageManager(), mCallingPackage); setFinishOnTouchOutside(false); setTitle(R.string.permission_request_title); // 请求的多个权限 mRequestedPermissions = getIntent().getStringArrayExtra( PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES); if (mRequestedPermissions == null) { mRequestedPermissions = new String[0]; } Log.e("temptag", "请求的多个权限:"+ Arrays.toString(mRequestedPermissions)); final int requestedPermCount = mRequestedPermissions.length; if (requestedPermCount == 0) { setResultAndFinish(); return; } PackageInfo callingPackageInfo = getCallingPackageInfo(); if (callingPackageInfo == null || callingPackageInfo.requestedPermissions == null || callingPackageInfo.requestedPermissions.length <= 0) { setResultAndFinish(); return; } // Don't allow legacy apps to request runtime permissions. if (callingPackageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { // Returning empty arrays means a cancellation. mRequestedPermissions = new String[0]; setResultAndFinish(); return; } mCallingUid = callingPackageInfo.applicationInfo.uid; UserHandle userHandle = UserHandle.getUserHandleForUid(mCallingUid); if (DeviceUtils.isTelevision(this)) { mViewHandler = new com.android.packageinstaller.permission.ui.television .GrantPermissionsViewHandlerImpl(this, mCallingPackage).setResultListener(this); } else if (DeviceUtils.isWear(this)) { mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this); } else if (DeviceUtils.isAuto(this)) { mViewHandler = new GrantPermissionsAutoViewHandler(this, mCallingPackage, userHandle) .setResultListener(this); } else { mViewHandler = new com.android.packageinstaller.permission.ui.handheld .GrantPermissionsViewHandlerImpl(this, mCallingPackage, userHandle) .setResultListener(this); } mAppPermissions = new AppPermissions(this, callingPackageInfo, false, new Runnable() { @Override public void run() { setResultAndFinish(); } }); // todo Set groupNames = new HashSet<>(); // 处理每一条请求的权限 for (String requestedPermission : mRequestedPermissions) { if (requestedPermission == null) { continue; } // 计算出相关的有影响的权限 ArrayList affectedPermissions = computeAffectedPermissions(requestedPermission); Log.e("temptag", "处理权限"+requestedPermission+"时:"); Log.e("temptag", "有相关权限"+ affectedPermissions.toString()); int numAffectedPermissions = affectedPermissions.size(); for (int i = 0; i < numAffectedPermissions; i++) { // 获取每条相关权限对应的权限组 AppPermissionGroup group = mAppPermissions.getGroupForPermission(affectedPermissions.get(i)); // 记下所有的权限组 groupNames.add(group.getName()); Log.e("temptag", "相关权限" + affectedPermissions.get(i) + "对应的权限组:" + group.getName()); if (group == null) { reportRequestResult(affectedPermissions.get(i), PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED); continue; } /// M: CTA requirement - permission control @{ if (Utils.CTA_SUPPORT) { // 从权限组里获取这个权限 Permission permission = group.getPermission(affectedPermissions.get(i)); if (permission == null) { continue; } Log.d(LOG_TAG, "mCallingPackage = " + mCallingPackage + "permission = " + permission.getName()); dealWithPermissionPolicyforCta(group, affectedPermissions.get(i), callingPackageInfo, permission); } else { Log.e("temptag", "Utils.CTA_SUPPORT=false 权限组新加入改权限"); addRequestedPermissions(group, affectedPermissions.get(i), icicle == null); } // /@} } } if(checkPermissionWhiteList(callingPackageInfo.packageName)){ for (String name : groupNames) { // String name = "android.permission-group.STORAGE"; Log.e("temptag", "权限组名:" + name); GroupState foregroundGroupState = getForegroundGroupState(name); GroupState backgroundGroupState = getBackgroundGroupState(name); if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, true, false); Log.e("temptag", "foregroundGroupState授权该权限组"); }else{ Log.e("temptag", "foregroundGroupState is null"); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, true, false); Log.e("temptag", "backgroundGroupState授权授权该权限组"); }else{ Log.e("temptag", "backgroundGroupState is null"); } } groupNames.clear(); setResultAndFinish(); } int numGroupStates = mRequestGrantPermissionGroups.size(); for (int groupStateNum = 0; groupStateNum < numGroupStates; groupStateNum++) { GroupState groupState = mRequestGrantPermissionGroups.valueAt(groupStateNum); AppPermissionGroup group = groupState.mGroup; // Restore permission group state after lifecycle events if (icicle != null) { groupState.mState = icicle.getInt( getInstanceStateKey(mRequestGrantPermissionGroups.keyAt(groupStateNum)), groupState.mState); } // Do not attempt to grant background access if foreground access is not either already // granted or requested if (group.isBackgroundGroup()) { // Check if a foreground permission is already granted boolean foregroundGroupAlreadyGranted = mAppPermissions.getPermissionGroup( group.getName()).areRuntimePermissionsGranted(); boolean hasForegroundRequest = (getForegroundGroupState(group.getName()) != null); if (!foregroundGroupAlreadyGranted && !hasForegroundRequest) { // The background permission cannot be granted at this time int numPermissions = groupState.affectedPermissions.length; for (int permissionNum = 0; permissionNum < numPermissions; permissionNum++) { Log.w(LOG_TAG, "Cannot grant " + groupState.affectedPermissions[permissionNum] + " as the matching foreground permission is not already " + "granted."); } groupState.mState = GroupState.STATE_SKIPPED; reportRequestResult(groupState.affectedPermissions, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED); } } } setContentView(mViewHandler.createView()); Window window = getWindow(); WindowManager.LayoutParams layoutParams = window.getAttributes(); mViewHandler.updateWindowAttributes(layoutParams); window.setAttributes(layoutParams); // Restore UI state after lifecycle events. This has to be before // showNextPermissionGroupGrantRequest is called. showNextPermissionGroupGrantRequest might // update the UI and the UI behaves differently for updates and initial creations. if (icicle != null) { mViewHandler.loadInstanceState(icicle); } if (!showNextPermissionGroupGrantRequest()) { setResultAndFinish(); } } /** * Update the {@link #mRequestedPermissions} if the system reports them as granted. * *

This also updates the {@link #mAppPermissions} state and switches to the next group grant * request if the current group becomes granted. */ private void updateIfPermissionsWereGranted() { PackageManager pm = getPackageManager(); boolean mightShowNextGroup = true; int numGroupStates = mRequestGrantPermissionGroups.size(); for (int i = 0; i < numGroupStates; i++) { GroupState groupState = mRequestGrantPermissionGroups.valueAt(i); if (groupState == null || groupState.mState != GroupState.STATE_UNKNOWN) { // Group has already been approved / denied via the UI by the user continue; } boolean allAffectedPermissionsOfThisGroupAreGranted = true; if (groupState.affectedPermissions == null) { // It is not clear which permissions belong to this group, hence never skip this // view allAffectedPermissionsOfThisGroupAreGranted = false; } else { for (int permNum = 0; permNum < groupState.affectedPermissions.length; permNum++) { if (pm.checkPermission(groupState.affectedPermissions[permNum], mCallingPackage) == PERMISSION_DENIED) { allAffectedPermissionsOfThisGroupAreGranted = false; break; } } } if (allAffectedPermissionsOfThisGroupAreGranted) { groupState.mState = GroupState.STATE_ALLOWED; if (mightShowNextGroup) { // The UI currently displays the first group with // mState == STATE_UNKNOWN. So we are switching to next group until we // could not allow a group that was still unknown if (!showNextPermissionGroupGrantRequest()) { setResultAndFinish(); } } } else { mightShowNextGroup = false; } } } @Override protected void onStart() { super.onStart(); try { mPermissionChangeListener = new PermissionChangeListener(); } catch (NameNotFoundException e) { setResultAndFinish(); return; } PackageManager pm = getPackageManager(); pm.addOnPermissionsChangeListener(mPermissionChangeListener); // get notified when the package is removed mPackageRemovalMonitor = new PackageRemovalMonitor(this, mCallingPackage) { @Override public void onPackageRemoved() { Log.w(LOG_TAG, mCallingPackage + " was uninstalled"); finish(); } }; mPackageRemovalMonitor.register(); // check if the package was removed while this activity was not started try { pm.getPackageInfo(mCallingPackage, 0); } catch (NameNotFoundException e) { Log.w(LOG_TAG, mCallingPackage + " was uninstalled while this activity was stopped", e); finish(); } updateIfPermissionsWereGranted(); } @Override protected void onStop() { super.onStop(); if (mPackageRemovalMonitor != null) { mPackageRemovalMonitor.unregister(); mPackageRemovalMonitor = null; } if (mPermissionChangeListener != null) { getPackageManager().removeOnPermissionsChangeListener(mPermissionChangeListener); mPermissionChangeListener = null; } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { View rootView = getWindow().getDecorView(); if (rootView.getTop() != 0) { // We are animating the top view, need to compensate for that in motion events. ev.setLocation(ev.getX(), ev.getY() - rootView.getTop()); } return super.dispatchTouchEvent(ev); } /** * Compose a key that stores the GroupState.mState in the instance state. * * @param requestGrantPermissionGroupsKey The key of the permission group * * @return A unique key to be used in the instance state */ private static String getInstanceStateKey( Pair requestGrantPermissionGroupsKey) { return GrantPermissionsActivity.class.getName() + "_" + requestGrantPermissionGroupsKey.first + "_" + requestGrantPermissionGroupsKey.second; } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mViewHandler != null) { mViewHandler.saveInstanceState(outState); } outState.putLong(KEY_REQUEST_ID, mRequestId); int numGroups = mRequestGrantPermissionGroups.size(); for (int i = 0; i < numGroups; i++) { int state = mRequestGrantPermissionGroups.valueAt(i).mState; if (state != GroupState.STATE_UNKNOWN) { outState.putInt(getInstanceStateKey(mRequestGrantPermissionGroups.keyAt(i)), state); } } } /** * @return the background group state for the permission group with the {@code name} */ private GroupState getBackgroundGroupState(String name) { return mRequestGrantPermissionGroups.get(new Pair<>(name, true)); } /** * @return the foreground group state for the permission group with the {@code name} */ private GroupState getForegroundGroupState(String name) { return mRequestGrantPermissionGroups.get(new Pair<>(name, false)); } private boolean shouldShowRequestForGroupState(GroupState groupState) { if (groupState.mState == GroupState.STATE_SKIPPED) { return false; } GroupState foregroundGroup = getForegroundGroupState(groupState.mGroup.getName()); if (groupState.mGroup.isBackgroundGroup() && (foregroundGroup != null && shouldShowRequestForGroupState(foregroundGroup))) { // If an app requests both foreground and background permissions of the same group, // we only show one request return false; } return true; } /// M: CTA requirement - permission control @{ private boolean showNextPermissionGroupGrantRequest() { if (Utils.CTA_SUPPORT) { return showNextPermissionGroupGrantRequestforCta(); } else { return showNextPermissionGroupGrantRequestforAosp(); } } ///@} /// M: CTA requirement - permission control @{ private boolean showNextPermissionGroupGrantRequestforAosp() { ///@} int numGroupStates = mRequestGrantPermissionGroups.size(); int numGrantRequests = 0; for (int i = 0; i < numGroupStates; i++) { if (shouldShowRequestForGroupState(mRequestGrantPermissionGroups.valueAt(i))) { numGrantRequests++; } } int currentIndex = 0; for (GroupState groupState : mRequestGrantPermissionGroups.values()) { if (!shouldShowRequestForGroupState(groupState)) { continue; } if (groupState.mState == GroupState.STATE_UNKNOWN) { GroupState foregroundGroupState; GroupState backgroundGroupState; if (groupState.mGroup.isBackgroundGroup()) { backgroundGroupState = groupState; foregroundGroupState = getForegroundGroupState(groupState.mGroup.getName()); } else { foregroundGroupState = groupState; backgroundGroupState = getBackgroundGroupState(groupState.mGroup.getName()); } CharSequence appLabel = mAppPermissions.getAppLabel(); Icon icon; try { icon = Icon.createWithResource(groupState.mGroup.getIconPkg(), groupState.mGroup.getIconResId()); } catch (Resources.NotFoundException e) { Log.e(LOG_TAG, "Cannot load icon for group" + groupState.mGroup.getName(), e); icon = null; } // If no background permissions are granted yet, we need to ask for background // permissions boolean needBackgroundPermission = false; boolean isBackgroundPermissionUserSet = false; if (backgroundGroupState != null) { if (!backgroundGroupState.mGroup.areRuntimePermissionsGranted()) { needBackgroundPermission = true; isBackgroundPermissionUserSet = backgroundGroupState.mGroup.isUserSet(); } } // If no foreground permissions are granted yet, we need to ask for foreground // permissions boolean needForegroundPermission = false; boolean isForegroundPermissionUserSet = false; if (foregroundGroupState != null) { if (!foregroundGroupState.mGroup.areRuntimePermissionsGranted()) { needForegroundPermission = true; isForegroundPermissionUserSet = foregroundGroupState.mGroup.isUserSet(); } } // The button doesn't show when its label is null mButtonLabels = new CharSequence[NUM_BUTTONS]; mButtonLabels[LABEL_ALLOW_BUTTON] = getString(R.string.grant_dialog_button_allow); mButtonLabels[LABEL_ALLOW_ALWAYS_BUTTON] = null; mButtonLabels[LABEL_ALLOW_FOREGROUND_BUTTON] = null; mButtonLabels[LABEL_DENY_BUTTON] = getString(R.string.grant_dialog_button_deny); if (isForegroundPermissionUserSet || isBackgroundPermissionUserSet) { mButtonLabels[LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON] = getString(R.string.grant_dialog_button_deny_and_dont_ask_again); } else { mButtonLabels[LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON] = null; } int messageId; int detailMessageId = 0; if (needForegroundPermission) { messageId = groupState.mGroup.getRequest(); if (groupState.mGroup.hasPermissionWithBackgroundMode()) { mButtonLabels[LABEL_ALLOW_BUTTON] = null; mButtonLabels[LABEL_ALLOW_FOREGROUND_BUTTON] = getString(R.string.grant_dialog_button_allow_foreground); if (needBackgroundPermission) { mButtonLabels[LABEL_ALLOW_ALWAYS_BUTTON] = getString(R.string.grant_dialog_button_allow_always); if (isForegroundPermissionUserSet || isBackgroundPermissionUserSet) { mButtonLabels[LABEL_DENY_BUTTON] = null; } } } else { detailMessageId = groupState.mGroup.getRequestDetail(); } } else { if (needBackgroundPermission) { messageId = groupState.mGroup.getBackgroundRequest(); detailMessageId = groupState.mGroup.getBackgroundRequestDetail(); mButtonLabels[LABEL_ALLOW_BUTTON] = getString(R.string.grant_dialog_button_allow_background); mButtonLabels[LABEL_DENY_BUTTON] = getString(R.string.grant_dialog_button_deny_background); mButtonLabels[LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON] = getString(R.string .grant_dialog_button_deny_background_and_dont_ask_again); } else { // Not reached as the permissions should be auto-granted return false; } } CharSequence message = getRequestMessage(appLabel, groupState.mGroup, this, messageId); Spanned detailMessage = null; if (detailMessageId != 0) { try { detailMessage = Html.fromHtml( getPackageManager().getResourcesForApplication( groupState.mGroup.getDeclaringPackage()).getString( detailMessageId), 0); } catch (NameNotFoundException ignored) { } } // Set the permission message as the title so it can be announced. setTitle(message); mViewHandler.updateUi(groupState.mGroup.getName(), numGrantRequests, currentIndex, icon, message, detailMessage, mButtonLabels); return true; } if (groupState.mState != GroupState.STATE_SKIPPED) { currentIndex++; } } return false; } @Override public void onPermissionGrantResult(String name, @GrantPermissionsViewHandler.Result int result) { logGrantPermissionActivityButtons(name, result); Log.e("temptag", "groupname=" + name + "授权结果:" + result); GroupState foregroundGroupState = getForegroundGroupState(name); GroupState backgroundGroupState = getBackgroundGroupState(name); if (result == GRANTED_ALWAYS || result == GRANTED_FOREGROUND_ONLY || result == DENIED_DO_NOT_ASK_AGAIN) { KeyguardManager kgm = getSystemService(KeyguardManager.class); if (kgm.isDeviceLocked()) { kgm.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() { @Override public void onDismissError() { Log.e(LOG_TAG, "Cannot dismiss keyguard perm=" + name + " result=" + result); } @Override public void onDismissCancelled() { // do nothing (i.e. stay at the current permission group) } @Override public void onDismissSucceeded() { // Now the keyguard is dismissed, hence the device is not locked // anymore onPermissionGrantResult(name, result); } }); return; } } if (!Utils.CTA_SUPPORT) { switch (result) { case GRANTED_ALWAYS : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, true, false); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, true, false); } break; case GRANTED_FOREGROUND_ONLY : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, true, false); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, false, false); } break; case DENIED : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, false, false); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, false, false); } break; case DENIED_DO_NOT_ASK_AGAIN : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, false, true); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, false, true); } break; } } else { /// M: CTA requirement - permission control @{ permissionGrantResultforCta(name, result); /// }@ } if (!showNextPermissionGroupGrantRequest()) { setResultAndFinish(); } } /** * Grants or revoked the affected permissions for a single {@link groupState}. * * @param groupState The group state with the permissions to grant/revoke * @param granted {@code true} if the permissions should be granted, {@code false} if they * should be revoked * @param doNotAskAgain if the permissions should be revoked should be app be allowed to ask * again for the same permissions? */ private void onPermissionGrantResultSingleState(GroupState groupState, boolean granted, boolean doNotAskAgain) { if (groupState != null && groupState.mGroup != null && groupState.mState == GroupState.STATE_UNKNOWN) { Log.e("temptag", "待授权的权限:"+Arrays.toString(groupState.affectedPermissions)); if (granted) { Log.e("temptag", "yes"); groupState.mGroup.grantRuntimePermissions(doNotAskAgain, groupState.affectedPermissions); groupState.mState = GroupState.STATE_ALLOWED; reportRequestResult(groupState.affectedPermissions, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED); } else { Log.e("temptag", "no"); groupState.mGroup.revokeRuntimePermissions(doNotAskAgain, groupState.affectedPermissions); groupState.mState = GroupState.STATE_DENIED; reportRequestResult(groupState.affectedPermissions, doNotAskAgain ? PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE : PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED); } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // We do not allow backing out. return keyCode == KeyEvent.KEYCODE_BACK; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // We do not allow backing out. return keyCode == KeyEvent.KEYCODE_BACK; } @Override public void finish() { setResultIfNeeded(RESULT_CANCELED); super.finish(); } private PackageInfo getCallingPackageInfo() { try { return getPackageManager().getPackageInfo(mCallingPackage, PackageManager.GET_PERMISSIONS); } catch (NameNotFoundException e) { Log.i(LOG_TAG, "No package: " + mCallingPackage, e); return null; } } private void setResultIfNeeded(int resultCode) { if (!mResultSet) { mResultSet = true; logRequestedPermissionGroups(); Intent result = new Intent(PackageManager.ACTION_REQUEST_PERMISSIONS); result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, mRequestedPermissions); PackageManager pm = getPackageManager(); if (mRequestedPermissions == null) { mRequestedPermissions = getIntent().getStringArrayExtra( PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES); if (mRequestedPermissions == null) { mRequestedPermissions = new String[0]; } } int numRequestedPermissions = mRequestedPermissions.length; int[] grantResults = new int[numRequestedPermissions]; for (int i = 0; i < numRequestedPermissions; i++) { grantResults[i] = pm.checkPermission(mRequestedPermissions[i], mCallingPackage); } result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS, grantResults); setResult(resultCode, result); } } private void setResultAndFinish() { setResultIfNeeded(RESULT_OK); finish(); } private void logRequestedPermissionGroups() { if (mRequestGrantPermissionGroups.isEmpty()) { return; } final int groupCount = mRequestGrantPermissionGroups.size(); List groups = new ArrayList<>(groupCount); for (GroupState groupState : mRequestGrantPermissionGroups.values()) { groups.add(groupState.mGroup); } SafetyNetLogger.logPermissionsRequested(mAppPermissions.getPackageInfo(), groups); } /** * Get the actually requested permissions when a permission is requested. * *

>In some cases requesting to grant a single permission requires the system to grant * additional permissions. E.g. before N-MR1 a single permission of a group caused the whole * group to be granted. Another case are permissions that are split into two. For apps that * target an SDK before the split, this method automatically adds the split off permission. * * @param permission The requested permission * * @return The actually requested permissions */ private ArrayList computeAffectedPermissions(String permission) { int requestingAppTargetSDK = mAppPermissions.getPackageInfo().applicationInfo.targetSdkVersion; // If a permission is split, all permissions the original permission is split into are // affected ArrayList extendedBySplitPerms = new ArrayList<>(); extendedBySplitPerms.add(permission); List splitPerms = getSystemService( PermissionManager.class).getSplitPermissions(); int numSplitPerms = splitPerms.size(); for (int i = 0; i < numSplitPerms; i++) { PermissionManager.SplitPermissionInfo splitPerm = splitPerms.get(i); if (requestingAppTargetSDK < splitPerm.getTargetSdk() && permission.equals(splitPerm.getSplitPermission())) { extendedBySplitPerms.addAll(splitPerm.getNewPermissions()); } } // For <= N_MR1 apps all permissions of the groups of the requested permissions are affected if (requestingAppTargetSDK <= Build.VERSION_CODES.N_MR1) { ArrayList extendedBySplitPermsAndGroup = new ArrayList<>(); int numExtendedBySplitPerms = extendedBySplitPerms.size(); for (int splitPermNum = 0; splitPermNum < numExtendedBySplitPerms; splitPermNum++) { AppPermissionGroup group = mAppPermissions.getGroupForPermission( extendedBySplitPerms.get(splitPermNum)); if (group == null) { continue; } ArrayList permissionsInGroup = group.getPermissions(); int numPermissionsInGroup = permissionsInGroup.size(); for (int permNum = 0; permNum < numPermissionsInGroup; permNum++) { extendedBySplitPermsAndGroup.add(permissionsInGroup.get(permNum).getName()); } } return extendedBySplitPermsAndGroup; } else { return extendedBySplitPerms; } } private void logGrantPermissionActivityButtons(String permissionGroupName, int grantResult) { int clickedButton = 0; int presentedButtons = getButtonState(); switch (grantResult) { case GRANTED_ALWAYS: if ((presentedButtons & (1 << LABEL_ALLOW_BUTTON)) != 0) { clickedButton = 1 << LABEL_ALLOW_BUTTON; } else { clickedButton = 1 << LABEL_ALLOW_ALWAYS_BUTTON; } break; case GRANTED_FOREGROUND_ONLY: clickedButton = 1 << LABEL_ALLOW_FOREGROUND_BUTTON; break; case DENIED: clickedButton = 1 << LABEL_DENY_BUTTON; break; case DENIED_DO_NOT_ASK_AGAIN: clickedButton = 1 << LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON; break; default: break; } PermissionControllerStatsLog.write(GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS, permissionGroupName, mCallingUid, mCallingPackage, presentedButtons, clickedButton); Log.v(LOG_TAG, "Logged buttons presented and clicked permissionGroupName=" + permissionGroupName + " uid=" + mCallingUid + " package=" + mCallingPackage + " presentedButtons=" + presentedButtons + " clickedButton=" + clickedButton); } private int getButtonState() { if (mButtonLabels == null) { return 0; } int buttonState = 0; for (int i = NUM_BUTTONS - 1; i >= 0; i--) { buttonState *= 2; if (mButtonLabels[i] != null) { buttonState++; } } return buttonState; } private static final class GroupState { static final int STATE_UNKNOWN = 0; static final int STATE_ALLOWED = 1; static final int STATE_DENIED = 2; static final int STATE_SKIPPED = 3; final AppPermissionGroup mGroup; int mState = STATE_UNKNOWN; /** Permissions of this group that need to be granted, null == no permissions of group */ String[] affectedPermissions; GroupState(AppPermissionGroup group) { mGroup = group; } } private class PermissionChangeListener implements PackageManager.OnPermissionsChangedListener { final int mCallingPackageUid; PermissionChangeListener() throws NameNotFoundException { mCallingPackageUid = getPackageManager().getPackageUid(mCallingPackage, 0); } @Override public void onPermissionsChanged(int uid) { if (uid == mCallingPackageUid) { updateIfPermissionsWereGranted(); } } } /// M: CTA requirement - permission control @{ private LinkedHashMap mRequestGrantPermissions = new LinkedHashMap<>(); private boolean showNextPermissionGroupGrantRequestforCta() { int permCount = mRequestGrantPermissions.size(); int currentIndex = 0; for (PermissionState permState : mRequestGrantPermissions.values()) { if (permState.getState() == PermissionState.STATE_UNKNOWN) { CharSequence appLabel = mAppPermissions.getAppLabel(); PermissionInfo permInfo; try { permInfo = getPackageManager() .getPermissionInfo(permState.getPermission().getName(), 0); } catch (NameNotFoundException e) { continue; } Icon icon; try { icon = Icon.createWithResource(permState.getAppPermissionGroup().getIconPkg(), permState.getAppPermissionGroup().getIconResId()); } catch (Resources.NotFoundException e) { Log.e(LOG_TAG, "Cannot load icon for group" + permState.getAppPermissionGroup().getName(), e); icon = null; } // The button doesn't show when its label is null CharSequence[] buttonLabels = new CharSequence[NUM_BUTTONS]; buttonLabels[LABEL_ALLOW_BUTTON] = getString(R.string.grant_dialog_button_allow); buttonLabels[LABEL_DENY_BUTTON] = getString(R.string.grant_dialog_button_deny); Spanned detailMessage = null; CharSequence message = Html.fromHtml(getString(R.string.permission_warning_template, appLabel, permInfo.loadLabel(getPackageManager())), 0); // Set the permission message as the title so it can be announced. setTitle(message); mViewHandler.updateUi(permState.getPermission().getName(), permCount, currentIndex, icon, message, detailMessage, buttonLabels); return true; } currentIndex++; } return false; } private void permissionGrantResultforCta(String name, @GrantPermissionsViewHandler.Result int result) { boolean granted = (result == GRANTED_ALWAYS); boolean doNotAskAgain = (result == DENIED_DO_NOT_ASK_AGAIN); PermissionState permState = mRequestGrantPermissions.get(name); if (permState != null && permState.getPermission() != null && permState.getAppPermissionGroup() != null) { if (granted) { permState.getAppPermissionGroup().grantRuntimePermissions(doNotAskAgain, new String[] { permState.getPermission().getName() }); permState.setState(PermissionState.STATE_ALLOWED); reportRequestResult(name, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED); } else { permState.getAppPermissionGroup().revokeRuntimePermissions(doNotAskAgain, new String[] { permState.getPermission().getName() }); permState.setState(PermissionState.STATE_DENIED); reportRequestResult(name, doNotAskAgain ? PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE : PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED); } } } private void dealWithPermissionPolicyforCta(AppPermissionGroup group, String permission, PackageInfo callingPackageInfo, Permission affectedPermission) { // We allow the user to choose only non-fixed permissions. A permission // is fixed either by device policy or the user denying with prejudice. if (affectedPermission.isUserFixed()) { reportRequestResult(permission, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED); return; } else if (affectedPermission.isPolicyFixed()) { reportRequestResult(permission, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED); return; } switch (getPermissionPolicy()) { case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: { if (!group.areRuntimePermissionsGranted()) { group.grantRuntimePermissions(false, new String[] { permission }); affectedPermission.setPolicyFixed(true); getPackageManager().updatePermissionFlags( affectedPermission.getName(), callingPackageInfo.packageName, PackageManager.FLAG_PERMISSION_POLICY_FIXED, PackageManager.FLAG_PERMISSION_POLICY_FIXED, group.getUser()); reportRequestResult(permission, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED); } } break; case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: { if (group.areRuntimePermissionsGranted()) { group.revokeRuntimePermissions(false, new String[] { permission }); affectedPermission.setPolicyFixed(true); getPackageManager().updatePermissionFlags( affectedPermission.getName(), callingPackageInfo.packageName, PackageManager.FLAG_PERMISSION_POLICY_FIXED, PackageManager.FLAG_PERMISSION_POLICY_FIXED, group.getUser()); reportRequestResult(permission, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED); } } break; default: { if (group.areRuntimePermissionsGranted()) { if(!affectedPermission.isGrantedIncludingAppOp()) { mRequestGrantPermissions.put(permission, new PermissionState(group, affectedPermission)); } else { group.grantRuntimePermissions(false, new String[] { permission }); reportRequestResult(permission, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED); } } else { mRequestGrantPermissions.put(permission, new PermissionState(group, affectedPermission)); } } break; } } ///@} }

  • 输出日志
E/temptag: 请求的多个权限:[android.permission.READ_EXTERNAL_STORAGE, android.permission.WRITE_EXTERNAL_STORAGE]


// 1权限
E/temptag: 处理权限android.permission.READ_EXTERNAL_STORAGE时:
E/temptag: 有相关权限[android.permission.READ_EXTERNAL_STORAGE, android.permission.ACCESS_MEDIA_LOCATION]
// 1.1
E/temptag: 相关权限android.permission.READ_EXTERNAL_STORAGE对应的权限组:android.permission-group.STORAGE
E/temptag: Utils.CTA_SUPPORT=false 权限组新加入改权限
E/temptag: 权限组android.permission-group.STORAGE加入新权限android.permission.READ_EXTERNAL_STORAGE
E/temptag: 新加groupstate=null
// 1.2
E/temptag: 相关权限android.permission.ACCESS_MEDIA_LOCATION对应的权限组:android.permission-group.STORAGE
E/temptag: Utils.CTA_SUPPORT=false 权限组新加入改权限
E/temptag: 权限组android.permission-group.STORAGE加入新权限android.permission.ACCESS_MEDIA_LOCATION
E/temptag: groupstate已经存在[android.permission.READ_EXTERNAL_STORAGE]

// 2权限
E/temptag: 处理权限android.permission.WRITE_EXTERNAL_STORAGE时:
E/temptag: 有相关权限[android.permission.WRITE_EXTERNAL_STORAGE, android.permission.READ_EXTERNAL_STORAGE]
// 2.1
E/temptag: 相关权限android.permission.WRITE_EXTERNAL_STORAGE对应的权限组:android.permission-group.STORAGE
E/temptag: Utils.CTA_SUPPORT=false 权限组新加入改权限
E/temptag: 权限组android.permission-group.STORAGE加入新权限android.permission.WRITE_EXTERNAL_STORAGE
E/temptag: groupstate已经存在[android.permission.READ_EXTERNAL_STORAGE, android.permission.ACCESS_MEDIA_LOCATION]
// 2.2
E/temptag: 相关权限android.permission.READ_EXTERNAL_STORAGE对应的权限组:android.permission-group.STORAGE
E/temptag: Utils.CTA_SUPPORT=false 权限组新加入改权限
E/temptag: 权限组android.permission-group.STORAGE加入新权限android.permission.READ_EXTERNAL_STORAGE
E/temptag: groupstate已经存在[android.permission.READ_EXTERNAL_STORAGE, android.permission.ACCESS_MEDIA_LOCATION, android.permission.WRITE_EXTERNAL_STORAGE]

// 3对权限组授权
E/temptag: 权限组名:android.permission-group.STORAGE
E/temptag: 待授权的权限:[android.permission.READ_EXTERNAL_STORAGE, android.permission.ACCESS_MEDIA_LOCATION, android.permission.WRITE_EXTERNAL_STORAGE]
E/temptag: yes
E/temptag: foregroundGroupState授权该权限组
E/temptag: backgroundGroupState is null
  • 此方法未解决的bug:第一次打开app,自动授权时,界面会有点不对劲