plataforma
RK3288 + Android 7.1
demanda
En la versión alta del SDK, el permiso de la aplicación de terceros para solicitar la ventana flotante se ha restringido en un paso.
Además de la solicitud para que el permiso se declare en la aplicación:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
También debe abrir los permisos en la configuración: la
aplicación puede verificar si los permisos se han obtenido a través del código:
AppOpsManager opsMgr = (AppOpsManager)getSystemService(APP_OPS_SERVICE);
int res = opsMgr.checkOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, Process.myUid(), getPackageName());
if(res != AppOpsManager.MODE_ALLOWED){
showToast(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW + " not allowed");
}
Puede lanzar una excepción:
java.lang.SecurityException: com.android.myapp from uid 10066 not allowed to perform SYSTEM_ALERT_WINDOW
Si necesita abrir de forma predeterminada, debe modificar el código correspondiente
modificar
frameworks / base / services / core / java / com / android / server / AppOpsService.java
private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
//判断是否包含在白名单中, 并将其置为edit 置为 true.
//否则, 默认情况下, 则返回空, 导致在应用或其它服务获取packageName时, 发现其并未获取任何操作权限
edit |= checkIfInWhitelist(packageName);
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
}
if (uidState.pkgOps == null) {
if (!edit) {
return null;
}
uidState.pkgOps = new ArrayMap<>();
}
Ops ops = uidState.pkgOps.get(packageName);
if (ops == null) {
if (!edit) {
return null;
}
boolean isPrivileged = false;
// This is the first time we have seen this package name under this uid,
// so let's make sure it is valid.
if (uid != 0) {
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid = -1;
try {
ApplicationInfo appInfo = ActivityThread.getPackageManager()
.getApplicationInfo(packageName,
PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.getUserId(uid));
if (appInfo != null) {
pkgUid = appInfo.uid;
isPrivileged = (appInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
} else {
if ("media".equals(packageName)) {
pkgUid = Process.MEDIA_UID;
isPrivileged = false;
} else if ("audioserver".equals(packageName)) {
pkgUid = Process.AUDIOSERVER_UID;
isPrivileged = false;
} else if ("cameraserver".equals(packageName)) {
pkgUid = Process.CAMERASERVER_UID;
isPrivileged = false;
}
}
} catch (RemoteException e) {
Slog.w(TAG, "Could not contact PackageManager", e);
}
if (pkgUid != uid) {
// Oops! The package name is not valid for the uid they are calling
// under. Abort.
RuntimeException ex = new RuntimeException("here");
ex.fillInStackTrace();
Slog.w(TAG, "Bad call: specified package " + packageName
+ " under uid " + uid + " but it is really " + pkgUid, ex);
return null;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
ops = new Ops(packageName, uidState, isPrivileged);
if(checkIfInWhitelist(packageName)){
//添加默认权限并设置为允许, 这里只加了SYTEM_ALERT_WINDOW
Op op = new Op(ops.uidState.uid, ops.packageName, AppOpsManager.OP_SYSTEM_ALERT_WINDOW);
op.mode = AppOpsManager.MODE_ALLOWED;
ops.put(op.op, op);
}
uidState.pkgOps.put(packageName, ops);
}
return ops;
}
//allow special package for some permission
//把需要添加默认权限的应用包名加入到白名单中.
private boolean checkIfInWhitelist(String pkg){
if("com.android.testapp".equals(pkg)){
return true;
}
//....更多应用
return false;
}
Código relacionado
Una vez instalada la aplicación, los permisos son el valor predeterminado, es decir, sin cambios , el valor predeterminado:
frameworks / base / core / java / android / app / AppOpsManager.java
public static final int OP_NONE = -1;
//..........
/** @hide */
public static final int OP_WRITE_SETTINGS = 23;
/** @hide */
public static final int OP_SYSTEM_ALERT_WINDOW = 24;
/**
* This specifies the default mode for each operation.
*/
private static int[] sOpDefaultMode = new int[] {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_DEFAULT, // OP_WRITE_SETTINGS
AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_DEFAULT, // OP_GET_USAGE_STATS
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ERRORED, // OP_MOCK_LOCATION
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND
};
AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW
- Obtenga el permiso de la aplicación en los paquetes de configuración
/ aplicaciones / Configuración / src / com / android / settings / applications / AppStateAppOpsBridge.java
public PermissionState getPermissionInfo(String pkg, int uid) {
PermissionState permissionState = new PermissionState(pkg, new UserHandle(UserHandle
.getUserId(uid)));
try {
permissionState.packageInfo = mIPackageManager.getPackageInfo(pkg,
PackageManager.GET_PERMISSIONS | PackageManager.MATCH_UNINSTALLED_PACKAGES,
permissionState.userHandle.getIdentifier());
// Check static permission state (whatever that is declared in package manifest)
String[] requestedPermissions = permissionState.packageInfo.requestedPermissions;
int[] permissionFlags = permissionState.packageInfo.requestedPermissionsFlags;
if (requestedPermissions != null) {
for (int i = 0; i < requestedPermissions.length; i++) {
if (doesAnyPermissionMatch(requestedPermissions[i], mPermissions)) {
permissionState.permissionDeclared = true;
if ((permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
permissionState.staticPermissionGranted = true;
break;
}
}
}
}
// Check app op state.
List<PackageOps> ops = mAppOpsManager.getOpsForPackage(uid, pkg, mAppOpsOpCodes);
if (ops != null && ops.size() > 0 && ops.get(0).getOps().size() > 0) {
permissionState.appOpMode = ops.get(0).getOps().get(0).getMode();
}
} catch (RemoteException e) {
Log.w(TAG, "PackageManager is dead. Can't get package info " + pkg, e);
}
return permissionState;
}
Si el elemento de configuración no se ha cambiado, mAppOpsManager.getOpsForPackage volverá vacío.
Si se ha cambiado, devolverá el valor cambiado