Merge "Allow apps to collect which appops were noted"
This commit is contained in:
committed by
Android (Google) Code Review
commit
8e6a69c3a2
@@ -4279,14 +4279,21 @@ package android.app {
|
||||
method public void checkPackage(int, @NonNull String);
|
||||
method public void finishOp(@NonNull String, int, @NonNull String);
|
||||
method public boolean isOpActive(@NonNull String, int, @NonNull String);
|
||||
method public int noteOp(@NonNull String, int, @NonNull String);
|
||||
method public int noteOpNoThrow(@NonNull String, int, @NonNull String);
|
||||
method public int noteProxyOp(@NonNull String, @NonNull String);
|
||||
method public int noteProxyOpNoThrow(@NonNull String, @NonNull String);
|
||||
method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
|
||||
method @Deprecated public int noteOp(@NonNull String, int, @NonNull String);
|
||||
method public int noteOp(@NonNull String, int, @Nullable String, @Nullable String);
|
||||
method @Deprecated public int noteOpNoThrow(@NonNull String, int, @NonNull String);
|
||||
method public int noteOpNoThrow(@NonNull String, int, @NonNull String, @Nullable String);
|
||||
method @Deprecated public int noteProxyOp(@NonNull String, @NonNull String);
|
||||
method public int noteProxyOp(@NonNull String, @Nullable String, int, @Nullable String);
|
||||
method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @NonNull String);
|
||||
method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
|
||||
method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String);
|
||||
method public static String permissionToOp(String);
|
||||
method public int startOp(@NonNull String, int, @NonNull String);
|
||||
method public int startOpNoThrow(@NonNull String, int, @NonNull String);
|
||||
method public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
|
||||
method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
|
||||
method public int startOp(@NonNull String, int, @Nullable String, @Nullable String);
|
||||
method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
|
||||
method public int startOpNoThrow(@NonNull String, int, @NonNull String, @Nullable String);
|
||||
method public void startWatchingActive(@NonNull String[], @NonNull java.util.concurrent.Executor, @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
|
||||
method public void startWatchingMode(@NonNull String, @Nullable String, @NonNull android.app.AppOpsManager.OnOpChangedListener);
|
||||
method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener);
|
||||
@@ -4338,6 +4345,14 @@ package android.app {
|
||||
field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
|
||||
}
|
||||
|
||||
public abstract static class AppOpsManager.AppOpsCollector {
|
||||
ctor public AppOpsManager.AppOpsCollector();
|
||||
method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
|
||||
method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
|
||||
method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
|
||||
method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
|
||||
}
|
||||
|
||||
public static interface AppOpsManager.OnOpActiveChangedListener {
|
||||
method public void onOpActiveChanged(@NonNull String, int, @NonNull String, boolean);
|
||||
}
|
||||
@@ -4458,6 +4473,17 @@ package android.app {
|
||||
field public String serviceDetails;
|
||||
}
|
||||
|
||||
public final class AsyncNotedAppOp implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public String getMessage();
|
||||
method @Nullable public String getNotingPackageName();
|
||||
method @IntRange(from=0) public int getNotingUid();
|
||||
method @NonNull public String getOp();
|
||||
method @IntRange(from=0) public long getTime();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.AsyncNotedAppOp> CREATOR;
|
||||
}
|
||||
|
||||
public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
|
||||
ctor public AuthenticationRequiredException(Throwable, android.app.PendingIntent);
|
||||
method public int describeContents();
|
||||
@@ -6267,6 +6293,10 @@ package android.app {
|
||||
public class StatusBarManager {
|
||||
}
|
||||
|
||||
public final class SyncNotedAppOp {
|
||||
method @NonNull public String getOp();
|
||||
}
|
||||
|
||||
@Deprecated public class TabActivity extends android.app.ActivityGroup {
|
||||
ctor @Deprecated public TabActivity();
|
||||
method @Deprecated public android.widget.TabHost getTabHost();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
19
core/java/android/app/AsyncNotedAppOp.aidl
Normal file
19
core/java/android/app/AsyncNotedAppOp.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.app;
|
||||
|
||||
parcelable AsyncNotedAppOp;
|
||||
245
core/java/android/app/AsyncNotedAppOp.java
Normal file
245
core/java/android/app/AsyncNotedAppOp.java
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.app;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.annotations.Immutable;
|
||||
import com.android.internal.util.DataClass;
|
||||
|
||||
/**
|
||||
* When an {@link AppOpsManager#noteOp(String, int, String, String) app-op is noted} and the
|
||||
* app the app-op is noted for has a {@link AppOpsManager.AppOpsCollector} registered the note-event
|
||||
* needs to be delivered to the collector. Usually this is done via an {@link SyncNotedAppOp}, but
|
||||
* in some cases this is not possible. In this case an {@link AsyncNotedAppOp} is send to the system
|
||||
* server and then forwarded to the {@link AppOpsManager.AppOpsCollector} in the app.
|
||||
*/
|
||||
@Immutable
|
||||
@DataClass(genEqualsHashCode = true,
|
||||
genAidl = true,
|
||||
genHiddenConstructor = true)
|
||||
// - We don't expose the opCode, but rather the public name of the op, hence use a non-standard
|
||||
// getter
|
||||
@DataClass.Suppress({"getOpCode"})
|
||||
public final class AsyncNotedAppOp implements Parcelable {
|
||||
/** Op that was noted */
|
||||
private final @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int mOpCode;
|
||||
|
||||
/** Uid that noted the op */
|
||||
private final @IntRange(from = 0) int mNotingUid;
|
||||
|
||||
/**
|
||||
* Package that noted the op. {@code null} if the package name that noted the op could be not
|
||||
* be determined (e.g. when the op is noted from native code).
|
||||
*/
|
||||
private final @Nullable String mNotingPackageName;
|
||||
|
||||
/** Message associated with the noteOp. This message is set by the app noting the op */
|
||||
private final @NonNull String mMessage;
|
||||
|
||||
/** Milliseconds since epoch when the op was noted */
|
||||
private final @IntRange(from = 0) long mTime;
|
||||
|
||||
/**
|
||||
* @return Op that was noted.
|
||||
*/
|
||||
public @NonNull String getOp() {
|
||||
return AppOpsManager.opToPublicName(mOpCode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.0.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
//
|
||||
// To regenerate run:
|
||||
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AsyncNotedAppOp.java
|
||||
//
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
|
||||
/**
|
||||
* Creates a new AsyncNotedAppOp.
|
||||
*
|
||||
* @param opCode
|
||||
* Op that was noted
|
||||
* @param notingUid
|
||||
* Uid that noted the op
|
||||
* @param notingPackageName
|
||||
* Package that noted the op
|
||||
* @param message
|
||||
* Message associated with the noteOp. This message is set by the app noting the op
|
||||
* @param time
|
||||
* Milliseconds since epoch when the op was noted
|
||||
* @hide
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public AsyncNotedAppOp(
|
||||
@IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int opCode,
|
||||
@IntRange(from = 0) int notingUid,
|
||||
@Nullable String notingPackageName,
|
||||
@NonNull String message,
|
||||
@IntRange(from = 0) long time) {
|
||||
this.mOpCode = opCode;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
IntRange.class, null, mOpCode,
|
||||
"from", 0,
|
||||
"to", AppOpsManager._NUM_OP - 1);
|
||||
this.mNotingUid = notingUid;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
IntRange.class, null, mNotingUid,
|
||||
"from", 0);
|
||||
this.mNotingPackageName = notingPackageName;
|
||||
this.mMessage = message;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mMessage);
|
||||
this.mTime = time;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
IntRange.class, null, mTime,
|
||||
"from", 0);
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
/**
|
||||
* Uid that noted the op
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @IntRange(from = 0) int getNotingUid() {
|
||||
return mNotingUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Package that noted the op
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @Nullable String getNotingPackageName() {
|
||||
return mNotingPackageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message associated with the noteOp. This message is set by the app noting the op
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull String getMessage() {
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Milliseconds since epoch when the op was noted
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @IntRange(from = 0) long getTime() {
|
||||
return mTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public boolean equals(Object o) {
|
||||
// You can override field equality logic by defining either of the methods like:
|
||||
// boolean fieldNameEquals(AsyncNotedAppOp other) { ... }
|
||||
// boolean fieldNameEquals(FieldType otherValue) { ... }
|
||||
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
@SuppressWarnings("unchecked")
|
||||
AsyncNotedAppOp that = (AsyncNotedAppOp) o;
|
||||
//noinspection PointlessBooleanExpression
|
||||
return true
|
||||
&& mOpCode == that.mOpCode
|
||||
&& mNotingUid == that.mNotingUid
|
||||
&& java.util.Objects.equals(mNotingPackageName, that.mNotingPackageName)
|
||||
&& java.util.Objects.equals(mMessage, that.mMessage)
|
||||
&& mTime == that.mTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int hashCode() {
|
||||
// You can override field hashCode logic by defining methods like:
|
||||
// int fieldNameHashCode() { ... }
|
||||
|
||||
int _hash = 1;
|
||||
_hash = 31 * _hash + mOpCode;
|
||||
_hash = 31 * _hash + mNotingUid;
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mNotingPackageName);
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mMessage);
|
||||
_hash = 31 * _hash + Long.hashCode(mTime);
|
||||
return _hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public void writeToParcel(android.os.Parcel dest, int flags) {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
byte flg = 0;
|
||||
if (mNotingPackageName != null) flg |= 0x4;
|
||||
dest.writeByte(flg);
|
||||
dest.writeInt(mOpCode);
|
||||
dest.writeInt(mNotingUid);
|
||||
if (mNotingPackageName != null) dest.writeString(mNotingPackageName);
|
||||
dest.writeString(mMessage);
|
||||
dest.writeLong(mTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int describeContents() { return 0; }
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public static final @NonNull Parcelable.Creator<AsyncNotedAppOp> CREATOR
|
||||
= new Parcelable.Creator<AsyncNotedAppOp>() {
|
||||
@Override
|
||||
public AsyncNotedAppOp[] newArray(int size) {
|
||||
return new AsyncNotedAppOp[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "RedundantCast"})
|
||||
public AsyncNotedAppOp createFromParcel(android.os.Parcel in) {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
byte flg = in.readByte();
|
||||
int opCode = in.readInt();
|
||||
int notingUid = in.readInt();
|
||||
String notingPackageName = (flg & 0x4) == 0 ? null : in.readString();
|
||||
String message = in.readString();
|
||||
long time = in.readLong();
|
||||
return new AsyncNotedAppOp(
|
||||
opCode,
|
||||
notingUid,
|
||||
notingPackageName,
|
||||
message,
|
||||
time);
|
||||
}
|
||||
};
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1566503083973L,
|
||||
codegenVersion = "1.0.0",
|
||||
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
|
||||
inputSignatures = "private final @android.annotation.IntRange(from=0L, to=90L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mNotingPackageName\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
}
|
||||
68
core/java/android/app/SyncNotedAppOp.java
Normal file
68
core/java/android/app/SyncNotedAppOp.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.app;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.annotations.Immutable;
|
||||
|
||||
/**
|
||||
* Description of an app-op that was noted for the current process.
|
||||
*
|
||||
* <p>This is either delivered after a
|
||||
* {@link AppOpsManager.AppOpsCollector#onNoted(SyncNotedAppOp) two way binder call} or
|
||||
* when the app
|
||||
* {@link AppOpsManager.AppOpsCollector#onSelfNoted(SyncNotedAppOp) notes an app-op for
|
||||
* itself}.
|
||||
*/
|
||||
@Immutable
|
||||
public final class SyncNotedAppOp {
|
||||
private final int mOpCode;
|
||||
|
||||
/**
|
||||
* @return The op that was noted.
|
||||
*/
|
||||
public @NonNull String getOp() {
|
||||
return AppOpsManager.opToPublicName(mOpCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new sync op description
|
||||
*
|
||||
* @param opCode The op that was noted
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public SyncNotedAppOp(@IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int opCode) {
|
||||
mOpCode = opCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof SyncNotedAppOp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mOpCode == ((SyncNotedAppOp) other).mOpCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mOpCode;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import static android.app.AppOpsManager.strOpToOp;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -74,6 +76,16 @@ public final class PermissionChecker {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #checkPermission(Context, String, int, int, String, String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@PermissionResult
|
||||
public static int checkPermission(@NonNull Context context, @NonNull String permission,
|
||||
int pid, int uid, @Nullable String packageName) {
|
||||
return checkPermission(context, permission, pid, uid, packageName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given package in a UID and PID has a given permission
|
||||
* and whether the app op that corresponds to this permission is allowed.
|
||||
@@ -84,12 +96,14 @@ public final class PermissionChecker {
|
||||
* @param uid The uid for which to check.
|
||||
* @param packageName The package name for which to check. If null the
|
||||
* the first package for the calling UID will be used.
|
||||
* @param message A message describing the reason the permission was checked
|
||||
*
|
||||
* @return The permission check result which is either {@link #PERMISSION_GRANTED}
|
||||
* or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
|
||||
*/
|
||||
@PermissionResult
|
||||
public static int checkPermission(@NonNull Context context, @NonNull String permission,
|
||||
int pid, int uid, @Nullable String packageName) {
|
||||
int pid, int uid, @Nullable String packageName, @Nullable String message) {
|
||||
if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
@@ -108,7 +122,8 @@ public final class PermissionChecker {
|
||||
packageName = packageNames[0];
|
||||
}
|
||||
|
||||
if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid) != AppOpsManager.MODE_ALLOWED) {
|
||||
if (appOpsManager.noteProxyOpNoThrow(strOpToOp(op), packageName, uid, message)
|
||||
!= AppOpsManager.MODE_ALLOWED) {
|
||||
return PERMISSION_DENIED_APP_OP;
|
||||
}
|
||||
|
||||
@@ -131,7 +146,17 @@ public final class PermissionChecker {
|
||||
public static int checkSelfPermission(@NonNull Context context,
|
||||
@NonNull String permission) {
|
||||
return checkPermission(context, permission, Process.myPid(),
|
||||
Process.myUid(), context.getPackageName());
|
||||
Process.myUid(), context.getPackageName(), null /* self access */);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #checkCallingPermission(Context, String, String, String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@PermissionResult
|
||||
public static int checkCallingPermission(@NonNull Context context,
|
||||
@NonNull String permission, @Nullable String packageName) {
|
||||
return checkCallingPermission(context, permission, packageName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,17 +167,29 @@ public final class PermissionChecker {
|
||||
* @param permission The permission to check.
|
||||
* @param packageName The package name making the IPC. If null the
|
||||
* the first package for the calling UID will be used.
|
||||
* @param message A message describing the reason the permission was checked
|
||||
*
|
||||
* @return The permission check result which is either {@link #PERMISSION_GRANTED}
|
||||
* or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
|
||||
*/
|
||||
@PermissionResult
|
||||
public static int checkCallingPermission(@NonNull Context context,
|
||||
@NonNull String permission, @Nullable String packageName) {
|
||||
@NonNull String permission, @Nullable String packageName, @Nullable String message) {
|
||||
if (Binder.getCallingPid() == Process.myPid()) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
return checkPermission(context, permission, Binder.getCallingPid(),
|
||||
Binder.getCallingUid(), packageName);
|
||||
Binder.getCallingUid(), packageName, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #checkCallingOrSelfPermission(Context, String, String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@PermissionResult
|
||||
public static int checkCallingOrSelfPermission(@NonNull Context context,
|
||||
@NonNull String permission) {
|
||||
return checkCallingOrSelfPermission(context, permission, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,15 +198,17 @@ public final class PermissionChecker {
|
||||
*
|
||||
* @param context Context for accessing resources.
|
||||
* @param permission The permission to check.
|
||||
* @param message A message describing the reason the permission was checked
|
||||
*
|
||||
* @return The permission check result which is either {@link #PERMISSION_GRANTED}
|
||||
* or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
|
||||
*/
|
||||
@PermissionResult
|
||||
public static int checkCallingOrSelfPermission(@NonNull Context context,
|
||||
@NonNull String permission) {
|
||||
@NonNull String permission, @Nullable String message) {
|
||||
String packageName = (Binder.getCallingPid() == Process.myPid())
|
||||
? context.getPackageName() : null;
|
||||
return checkPermission(context, permission, Binder.getCallingPid(),
|
||||
Binder.getCallingUid(), packageName);
|
||||
Binder.getCallingUid(), packageName, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.app.AppOpsManager;
|
||||
import android.util.ExceptionUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
@@ -1029,7 +1030,17 @@ public class Binder implements IBinder {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, getClass().getName() + ":"
|
||||
+ (transactionName != null ? transactionName : code));
|
||||
}
|
||||
res = onTransact(code, data, reply, flags);
|
||||
|
||||
if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) {
|
||||
AppOpsManager.startNotedAppOpsCollection(callingUid);
|
||||
try {
|
||||
res = onTransact(code, data, reply, flags);
|
||||
} finally {
|
||||
AppOpsManager.finishNotedAppOpsCollection();
|
||||
}
|
||||
} else {
|
||||
res = onTransact(code, data, reply, flags);
|
||||
}
|
||||
} catch (RemoteException|RuntimeException e) {
|
||||
if (observer != null) {
|
||||
observer.callThrewException(callSession, e);
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AppOpsManager;
|
||||
import android.util.Log;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
@@ -506,9 +507,18 @@ public final class BinderProxy implements IBinder {
|
||||
}
|
||||
}
|
||||
|
||||
final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
|
||||
AppOpsManager.pauseNotedAppOpsCollection();
|
||||
|
||||
if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isCollectingNotedAppOps()) {
|
||||
flags |= FLAG_COLLECT_NOTED_APP_OPS;
|
||||
}
|
||||
|
||||
try {
|
||||
return transactNative(code, data, reply, flags);
|
||||
} finally {
|
||||
AppOpsManager.resumeNotedAppOpsCollection(prevCollection);
|
||||
|
||||
if (transactListener != null) {
|
||||
transactListener.onTransactEnded(session);
|
||||
}
|
||||
|
||||
@@ -169,6 +169,11 @@ public interface IBinder {
|
||||
*/
|
||||
int FLAG_ONEWAY = 0x00000001;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
int FLAG_COLLECT_NOTED_APP_OPS = 0x00000002;
|
||||
|
||||
/**
|
||||
* Limit that should be placed on IPC sizes to keep them safely under the
|
||||
* transaction buffer limit.
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.app.AppOpsManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -267,7 +268,9 @@ public final class Parcel {
|
||||
private static final int EX_UNSUPPORTED_OPERATION = -7;
|
||||
private static final int EX_SERVICE_SPECIFIC = -8;
|
||||
private static final int EX_PARCELABLE = -9;
|
||||
private static final int EX_HAS_REPLY_HEADER = -128; // special; see below
|
||||
/** @hide */
|
||||
public static final int EX_HAS_NOTED_APPOPS_REPLY_HEADER = -127; // special; see below
|
||||
private static final int EX_HAS_STRICTMODE_REPLY_HEADER = -128; // special; see below
|
||||
// EX_TRANSACTION_FAILED is used exclusively in native code.
|
||||
// see libbinder's binder/Status.h
|
||||
private static final int EX_TRANSACTION_FAILED = -129;
|
||||
@@ -1866,6 +1869,8 @@ public final class Parcel {
|
||||
* @see #readException
|
||||
*/
|
||||
public final void writeException(@NonNull Exception e) {
|
||||
AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
|
||||
|
||||
int code = 0;
|
||||
if (e instanceof Parcelable
|
||||
&& (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
|
||||
@@ -1944,6 +1949,8 @@ public final class Parcel {
|
||||
* @see #readException
|
||||
*/
|
||||
public final void writeNoException() {
|
||||
AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
|
||||
|
||||
// Despite the name of this function ("write no exception"),
|
||||
// it should instead be thought of as "write the RPC response
|
||||
// header", but because this function name is written out by
|
||||
@@ -1951,14 +1958,14 @@ public final class Parcel {
|
||||
//
|
||||
// The response header, in the non-exception case (see also
|
||||
// writeException above, also called by the AIDL compiler), is
|
||||
// either a 0 (the default case), or EX_HAS_REPLY_HEADER if
|
||||
// either a 0 (the default case), or EX_HAS_STRICTMODE_REPLY_HEADER if
|
||||
// StrictMode has gathered up violations that have occurred
|
||||
// during a Binder call, in which case we write out the number
|
||||
// of violations and their details, serialized, before the
|
||||
// actual RPC respons data. The receiving end of this is
|
||||
// readException(), below.
|
||||
if (StrictMode.hasGatheredViolations()) {
|
||||
writeInt(EX_HAS_REPLY_HEADER);
|
||||
writeInt(EX_HAS_STRICTMODE_REPLY_HEADER);
|
||||
final int sizePosition = dataPosition();
|
||||
writeInt(0); // total size of fat header, to be filled in later
|
||||
StrictMode.writeGatheredViolationsToParcel(this);
|
||||
@@ -2005,7 +2012,13 @@ public final class Parcel {
|
||||
@TestApi
|
||||
public final int readExceptionCode() {
|
||||
int code = readInt();
|
||||
if (code == EX_HAS_REPLY_HEADER) {
|
||||
if (code == EX_HAS_NOTED_APPOPS_REPLY_HEADER) {
|
||||
AppOpsManager.readAndLogNotedAppops(this);
|
||||
// Read next header or real exception if there is no more header
|
||||
code = readInt();
|
||||
}
|
||||
|
||||
if (code == EX_HAS_STRICTMODE_REPLY_HEADER) {
|
||||
int headerSize = readInt();
|
||||
if (headerSize == 0) {
|
||||
Log.e(TAG, "Unexpected zero-sized Parcel reply header.");
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.internal.app;
|
||||
|
||||
import android.app.AsyncNotedAppOp;
|
||||
|
||||
// Interface to observe async noted appops
|
||||
oneway interface IAppOpsAsyncNotedCallback {
|
||||
void opNoted(in AsyncNotedAppOp op);
|
||||
}
|
||||
@@ -17,12 +17,13 @@
|
||||
package com.android.internal.app;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AsyncNotedAppOp;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteCallback;
|
||||
import com.android.internal.app.IAppOpsCallback;
|
||||
import com.android.internal.app.IAppOpsActiveCallback;
|
||||
import com.android.internal.app.IAppOpsAsyncNotedCallback;
|
||||
import com.android.internal.app.IAppOpsNotedCallback;
|
||||
|
||||
interface IAppOpsService {
|
||||
@@ -40,6 +41,9 @@ interface IAppOpsService {
|
||||
IBinder getToken(IBinder clientToken);
|
||||
int permissionToOpCode(String permission);
|
||||
int checkAudioOperation(int code, int usage, int uid, String packageName);
|
||||
void noteAsyncOp(String callingPackageName, int uid, String packageName, int opCode,
|
||||
String message);
|
||||
boolean shouldCollectNotes(int opCode);
|
||||
// End of methods also called by native code.
|
||||
// Any new method exposed to native must be added after the last one, do not reorder
|
||||
|
||||
@@ -82,6 +86,10 @@ interface IAppOpsService {
|
||||
void startWatchingNoted(in int[] ops, IAppOpsNotedCallback callback);
|
||||
void stopWatchingNoted(IAppOpsNotedCallback callback);
|
||||
|
||||
void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback);
|
||||
void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback);
|
||||
List<AsyncNotedAppOp> extractAsyncOps(String packageName);
|
||||
|
||||
int checkOperationRaw(int code, int uid, String packageName);
|
||||
|
||||
void reloadNonHistoricalState();
|
||||
|
||||
@@ -61,16 +61,52 @@ public class AnnotationValidations {
|
||||
}
|
||||
|
||||
public static void validate(Class<IntRange> annotation, IntRange ignored, int value,
|
||||
String paramName1, int param1, String paramName2, int param2) {
|
||||
String paramName1, long param1, String paramName2, long param2) {
|
||||
validate(annotation, ignored, value, paramName1, param1);
|
||||
validate(annotation, ignored, value, paramName2, param2);
|
||||
}
|
||||
|
||||
public static void validate(Class<IntRange> annotation, IntRange ignored, int value,
|
||||
String paramName, int param) {
|
||||
String paramName, long param) {
|
||||
switch (paramName) {
|
||||
case "from": if (value < param) invalid(annotation, value, paramName, param); break;
|
||||
case "to": if (value > param) invalid(annotation, value, paramName, param); break;
|
||||
case "from":
|
||||
if (value < param) {
|
||||
invalid(annotation, value, paramName, param);
|
||||
}
|
||||
break;
|
||||
case "to":
|
||||
if (value > param) {
|
||||
invalid(annotation, value, paramName, param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a long value with two parameters.
|
||||
*/
|
||||
public static void validate(Class<IntRange> annotation, IntRange ignored, long value,
|
||||
String paramName1, long param1, String paramName2, long param2) {
|
||||
validate(annotation, ignored, value, paramName1, param1);
|
||||
validate(annotation, ignored, value, paramName2, param2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a long value with one parameter.
|
||||
*/
|
||||
public static void validate(Class<IntRange> annotation, IntRange ignored, long value,
|
||||
String paramName, long param) {
|
||||
switch (paramName) {
|
||||
case "from":
|
||||
if (value < param) {
|
||||
invalid(annotation, value, paramName, param);
|
||||
}
|
||||
break;
|
||||
case "to":
|
||||
if (value > param) {
|
||||
invalid(annotation, value, paramName, param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,11 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION;
|
||||
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
|
||||
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
|
||||
import static android.app.AppOpsManager.UID_STATE_TOP;
|
||||
import static android.app.AppOpsManager._NUM_OP;
|
||||
import static android.app.AppOpsManager.modeToName;
|
||||
import static android.app.AppOpsManager.opToName;
|
||||
import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
|
||||
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
@@ -49,6 +51,7 @@ import android.app.AppOpsManager.OpEntry;
|
||||
import android.app.AppOpsManager.OpFlags;
|
||||
import android.app.AppOpsManagerInternal;
|
||||
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
|
||||
import android.app.AsyncNotedAppOp;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -58,6 +61,7 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.media.AudioAttributes;
|
||||
@@ -69,6 +73,7 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
@@ -86,6 +91,7 @@ import android.util.AtomicFile;
|
||||
import android.util.KeyValueListParser;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.LongSparseLongArray;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
@@ -96,6 +102,7 @@ import android.util.Xml;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.IAppOpsActiveCallback;
|
||||
import com.android.internal.app.IAppOpsAsyncNotedCallback;
|
||||
import com.android.internal.app.IAppOpsCallback;
|
||||
import com.android.internal.app.IAppOpsNotedCallback;
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
@@ -181,6 +188,8 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
OP_CAMERA,
|
||||
};
|
||||
|
||||
private static final int MAX_UNFORWARED_OPS = 10;
|
||||
|
||||
Context mContext;
|
||||
final AtomicFile mFile;
|
||||
final Handler mHandler;
|
||||
@@ -188,6 +197,29 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
private final AppOpsManagerInternalImpl mAppOpsManagerInternal
|
||||
= new AppOpsManagerInternalImpl();
|
||||
|
||||
/**
|
||||
* Registered callbacks, called from {@link #noteAsyncOp}.
|
||||
*
|
||||
* <p>(package name, uid) -> callbacks
|
||||
*
|
||||
* @see #getAsyncNotedOpsKey(String, int)
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private final ArrayMap<Pair<String, Integer>, RemoteCallbackList<IAppOpsAsyncNotedCallback>>
|
||||
mAsyncOpWatchers = new ArrayMap<>();
|
||||
|
||||
/**
|
||||
* Async note-ops collected from {@link #noteAsyncOp} that have not been delivered to a
|
||||
* callback yet.
|
||||
*
|
||||
* <p>(package name, uid) -> list<ops>
|
||||
*
|
||||
* @see #getAsyncNotedOpsKey(String, int)
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private final ArrayMap<Pair<String, Integer>, ArrayList<AsyncNotedAppOp>>
|
||||
mUnforwardedAsyncNotedOps = new ArrayMap<>();
|
||||
|
||||
boolean mWriteScheduled;
|
||||
boolean mFastWriteScheduled;
|
||||
final Runnable mWriteRunner = new Runnable() {
|
||||
@@ -2097,6 +2129,141 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noteAsyncOp(String callingPackageName, int uid, String packageName, int opCode,
|
||||
String message) {
|
||||
Preconditions.checkNotNull(message);
|
||||
Preconditions.checkNotNull(packageName);
|
||||
verifyAndGetIsPrivileged(uid, packageName);
|
||||
|
||||
verifyIncomingUid(uid);
|
||||
verifyIncomingOp(opCode);
|
||||
|
||||
int callingUid = Binder.getCallingUid();
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (callingPackageName != null) {
|
||||
verifyAndGetIsPrivileged(callingUid, callingPackageName);
|
||||
}
|
||||
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (this) {
|
||||
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
|
||||
|
||||
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
|
||||
AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
|
||||
callingPackageName, message, now);
|
||||
final boolean[] wasNoteForwarded = {false};
|
||||
|
||||
if (callbacks != null) {
|
||||
callbacks.broadcast((cb) -> {
|
||||
try {
|
||||
cb.opNoted(asyncNotedOp);
|
||||
wasNoteForwarded[0] = true;
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG,
|
||||
"Could not forward noteOp of " + opCode + " to " + packageName
|
||||
+ "/" + uid, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!wasNoteForwarded[0]) {
|
||||
ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
|
||||
if (unforwardedOps == null) {
|
||||
unforwardedOps = new ArrayList<>(1);
|
||||
mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
|
||||
}
|
||||
|
||||
unforwardedOps.add(asyncNotedOp);
|
||||
if (unforwardedOps.size() > MAX_UNFORWARED_OPS) {
|
||||
unforwardedOps.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a key to be used in {@link #mAsyncOpWatchers} and {@link #mUnforwardedAsyncNotedOps}
|
||||
*
|
||||
* @param packageName The package name of the app
|
||||
* @param uid The uid of the app
|
||||
*
|
||||
* @return They key uniquely identifying the app
|
||||
*/
|
||||
private @NonNull Pair<String, Integer> getAsyncNotedOpsKey(@NonNull String packageName,
|
||||
int uid) {
|
||||
return new Pair<>(packageName, uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
|
||||
Preconditions.checkNotNull(packageName);
|
||||
Preconditions.checkNotNull(callback);
|
||||
|
||||
int uid = Binder.getCallingUid();
|
||||
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
|
||||
|
||||
verifyAndGetIsPrivileged(uid, packageName);
|
||||
|
||||
synchronized (this) {
|
||||
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
|
||||
if (callbacks == null) {
|
||||
callbacks = new RemoteCallbackList<IAppOpsAsyncNotedCallback>() {
|
||||
@Override
|
||||
public void onCallbackDied(IAppOpsAsyncNotedCallback callback) {
|
||||
synchronized (AppOpsService.this) {
|
||||
if (getRegisteredCallbackCount() == 0) {
|
||||
mAsyncOpWatchers.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
mAsyncOpWatchers.put(key, callbacks);
|
||||
}
|
||||
|
||||
callbacks.register(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
|
||||
Preconditions.checkNotNull(packageName);
|
||||
Preconditions.checkNotNull(callback);
|
||||
|
||||
int uid = Binder.getCallingUid();
|
||||
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
|
||||
|
||||
verifyAndGetIsPrivileged(uid, packageName);
|
||||
|
||||
synchronized (this) {
|
||||
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
|
||||
if (callbacks != null) {
|
||||
callbacks.unregister(callback);
|
||||
if (callbacks.getRegisteredCallbackCount() == 0) {
|
||||
mAsyncOpWatchers.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
|
||||
Preconditions.checkNotNull(packageName);
|
||||
|
||||
int uid = Binder.getCallingUid();
|
||||
|
||||
verifyAndGetIsPrivileged(uid, packageName);
|
||||
|
||||
synchronized (this) {
|
||||
return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int startOperation(IBinder token, int code, int uid, String packageName,
|
||||
boolean startIfModeDefault) {
|
||||
@@ -2340,6 +2507,25 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
return AppOpsManager.permissionToOpCode(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCollectNotes(int opCode) {
|
||||
Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
|
||||
|
||||
String perm = AppOpsManager.opToPermission(opCode);
|
||||
if (perm == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PermissionInfo permInfo;
|
||||
try {
|
||||
permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return permInfo.getProtection() == PROTECTION_DANGEROUS;
|
||||
}
|
||||
|
||||
void finishOperationLocked(Op op, boolean finishNested) {
|
||||
final int opCode = op.op;
|
||||
final int uid = op.uidState.uid;
|
||||
|
||||
Reference in New Issue
Block a user