Android 6.0 修改系统权限分析(二)

2/13/2017来源:iOS开发人气:1331

Android 6.0中,除了危险权限不再在安装后授予,还有两个特殊权限:SYSTEM_ALERT_WINDOW(设置悬浮窗,进行一些黑科技)和WRITE_SETTINGS(修改系统设置)。这里我们来分析WRITE_SETTINGS权限。 WRITE_SETTINGS权限 官方API说明 Note: If the app targets API level 23 or higher, the app user must explicitly grant this permission to the app through a permission management screen. The app requests the user's apPRoval by sending an intent with action ACTION_MANAGE_WRITE_SETTINGS. The app can check whether it has this authorization by calling Settings.System.canWrite().
/**
 * Checks if the specified app can modify system settings. As of API
 * level 23, an app cannot modify system settings unless it declares the
 * {@link android.Manifest.permission#WRITE_SETTINGS}
 * permission in its manifest, <em>and</em> the user specifically grants
 * the app this capability. To prompt the user to grant this approval,
 * the app must send an intent with the action {@link
 * android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}, which causes
 * the system to display a permission management screen.
 *
 * @param context App context.
 * @return true if the calling app can write to system settings, false otherwise
 */
public static boolean canWrite(Context context) {
    return isCallingPackageAllowedToWriteSettings(context, Process.myUid(),
            context.getOpPackageName(), false);

}


canWrite接口只要在API为23才能使用,用于判断是否具有WRITE_SETTINGS的权限,下面我们进一步分析

public static boolean isCallingPackageAllowedToPerformAppOpsProtectedOperation(Context context,
        int uid, String callingPackage, boolean throwException, int appOpsOpCode, String[]
        permissions, boolean makeNote) {
    if (callingPackage == null) {
        return false;
    }

    AppOpsManager appOpsMgr = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    int mode = AppOpsManager.MODE_DEFAULT;
    if (makeNote) {
        mode = appOpsMgr.noteOpNoThrow(appOpsOpCode, uid, callingPackage);
    } else {
        mode = appOpsMgr.checkOpNoThrow(appOpsOpCode, uid, callingPackage);
    }

    switch (mode) {
        case AppOpsManager.MODE_ALLOWED:
            return true;

        case AppOpsManager.MODE_DEFAULT:
            // this is the default operating mode after an app's installation
            // In this case we will check all associated static permission to see
            // if it is granted during install time.
            for (String permission : permissions) {
                if (context.checkCallingOrSelfPermission(permission) == PackageManager
                        .PERMISSION_GRANTED) {
                    // if either of the permissions are granted, we will allow it
                    return true;
                }
            }

        default:
            // this is for all other cases trickled down here...
            if (!throwException) {
                return false;
            }

    }


isCallingPackageAllowedToPerformAppOpsProtectedOperation传入了uid,包名以及permission等参数,其中mode参数默认为AppOpsManager.MODE_DEFAULT,直接跳到switch进行分析
MODE_DETAULT,则通过context.checkCallingOrSelfPermission(permission) 直接判断权限是否授予,这个跟Android系统权限的机制是有关系的,APP在第一次进入时,也就是权限没有经过手动修改(全部允许)的情况下,只要你在manifest进行了声明,就返回true,但是,如果你拒绝了某一项权限或者去手动关闭了某个权限之后,就会进入default分支,return false,又或者你手动打开了某个权限,则进入了AppOpsManager.MODE_ALLOWED分支直接return为true,下面我们继续分析
mode = appOpsMgr.checkOpNoThrow(appOpsOpCode,uid,
callingPackage);来进一步证明。

/**
 * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
 * returns {@link #MODE_ERRORED}.
 * @hide
 */
public int checkOpNoThrow(int op, int uid, String packageName) {
    try {
        return mService.checkOperation(op, uid, packageName);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }

}

final IAppOpsService mService;


mService是IAppOpsService的对象,根据Binder机制,我们找到server端的实现类AppOpsService

public int checkOperation(int code, int uid, String packageName) {



         verifyIncomingUid(uid);



         verifyIncomingOp(code);



         synchronized (this) {



             if (isOpRestricted(uid, code, packageName)) {



                 return AppOpsManager.MODE_IGNORED;



             }



             Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);



             if (op == null) {



                 return AppOpsManager.opToDefaultMode(code);



             }



return
 op.mode;

}
}


private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {



         HashMap<String, Ops> pkgOps = mUidOps.get(uid);



         if (pkgOps == null) {



             if (!edit) {



                 return null;



             }



             pkgOps = new HashMap<String, Ops>();


             mUidOps.put(uid, pkgOps);



         }



         Ops ops = pkgOps.get(packageName);


                    ...
}

final SparseArray<HashMap<String, Ops>> mUidOps 
= new 
SparseArray<HashMap<String,Ops>>();



根据uid,通过mUidOps获取到一个HashMap,这个HashMap是以包名为key,value为OPS的,所以一些设置了相同ShareUserId具有相同的uid的应用,只要包名不同,ops就不同,设置权限互不干扰。下面我们看看OP和OPS到底是什么。


public final static class Ops extends SparseArray<Op> {


         public final String packageName;



         public final int uid;


         public final boolean isPrivileged;


         public Ops(String _packageName, int _uid, boolean _isPrivileged) {


             packageName = _packageName;



             uid = _uid;


             isPrivileged = _isPrivileged;


         }



     }
OPS是一个OP的SparseArray集合,分析里面应该包含了所有的权限,这些权限op以int code为可以,code可以在checkOperation方法中找到,每个permission对应一个code,我们不在分析。



public 
final staticclass

Op
 {


         public final int uid;


         public final String packageName;



         public final int op;



         public int mode;


         public int duration;


         public long time;


         public long rejectTime;


         public int nesting;



         public Op(int _uid, String _packageName, int _op) {


             uid = _uid;


             packageName = _packageName;


             op = _op;


             mode = AppOpsManager.opToDefaultMode(op);


         }


     }


op中的mode正是我们要找到的mode,mode的定义

/**
 * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
 * allowed to perform the given operation.
 */
public static final int MODE_ALLOWED = 0;

/**
 * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
 * not allowed to perform the given operation, and this attempt should
 * <em>silently fail</em> (it should not cause the app to crash).
 */
public static final int MODE_IGNORED = 1;

/**
 * Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: the
 * given caller is not allowed to perform the given operation, and this attempt should
 * cause it to have a fatal error, typically a {@link SecurityException}.
 */
public static final int MODE_ERRORED = 2;

/**
 * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller should
 * use its default security check.  This mode is not normally used; it should only be used
 * with appop permissions, and callers must explicitly check for it and deal with it.
 */
public static final int MODE_DEFAULT = 3;




至此,我们通过分析WRITE_SETTINGS权限间接的了解到了Android整个权限系统是如何管理的,如果想更加全面的了解,请自行查看AppOpsService。