From 6e80c19a48334fffeb551a0c5b68d17ad7ecd11f Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Wed, 28 Mar 2018 11:29:40 +0100 Subject: [PATCH] StrictMode: Add support for warning on non SDK API usage. Adds new API methods to enable and disable these warnings. (cherry-picked from commit ad1b2a9cc1d43e7d36e46b0afce65fb981b189bc) Bug: 73896556 Test: StrictModeTest Change-Id: I096ce4c355c79cde1b98c3f48d392cd0b2ea5d98 --- api/current.txt | 5 +++ api/test-current.txt | 1 + core/java/android/os/StrictMode.java | 44 ++++++++++++++++++- .../os/strictmode/NonSdkApiUsedViolation.java | 28 ++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 core/java/android/os/strictmode/NonSdkApiUsedViolation.java diff --git a/api/current.txt b/api/current.txt index f1a3a9d3f145f..761fd335c55b8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -33159,6 +33159,7 @@ package android.os { method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects(); method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects(); method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects(); + method public android.os.StrictMode.VmPolicy.Builder detectNonSdkApiUsage(); method public android.os.StrictMode.VmPolicy.Builder detectUntaggedSockets(); method public android.os.StrictMode.VmPolicy.Builder penaltyDeath(); method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork(); @@ -33166,6 +33167,7 @@ package android.os { method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox(); method public android.os.StrictMode.VmPolicy.Builder penaltyListener(java.util.concurrent.Executor, android.os.StrictMode.OnVmViolationListener); method public android.os.StrictMode.VmPolicy.Builder penaltyLog(); + method public android.os.StrictMode.VmPolicy.Builder permitNonSdkApiUsage(); method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int); } @@ -33580,6 +33582,9 @@ package android.os.strictmode { public final class NetworkViolation extends android.os.strictmode.Violation { } + public final class NonSdkApiUsedViolation extends android.os.strictmode.Violation { + } + public final class ResourceMismatchViolation extends android.os.strictmode.Violation { } diff --git a/api/test-current.txt b/api/test-current.txt index 9f5fa0cb08634..9153a39d874ac 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -527,6 +527,7 @@ package android.os { field public static final int DETECT_VM_CURSOR_LEAKS = 256; // 0x100 field public static final int DETECT_VM_FILE_URI_EXPOSURE = 8192; // 0x2000 field public static final int DETECT_VM_INSTANCE_LEAKS = 2048; // 0x800 + field public static final int DETECT_VM_NON_SDK_API_USAGE = 1073741824; // 0x40000000 field public static final int DETECT_VM_REGISTRATION_LEAKS = 4096; // 0x1000 field public static final int DETECT_VM_UNTAGGED_SOCKET = -2147483648; // 0x80000000 } diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 1ab77ce546127..16d5be4e0c45f 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -40,6 +40,7 @@ import android.os.strictmode.InstanceCountViolation; import android.os.strictmode.IntentReceiverLeakedViolation; import android.os.strictmode.LeakedClosableViolation; import android.os.strictmode.NetworkViolation; +import android.os.strictmode.NonSdkApiUsedViolation; import android.os.strictmode.ResourceMismatchViolation; import android.os.strictmode.ServiceConnectionLeakedViolation; import android.os.strictmode.SqliteObjectLeakedViolation; @@ -77,6 +78,7 @@ import java.util.HashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; /** * StrictMode is a developer tool which detects things you might be doing by accident and brings @@ -267,6 +269,9 @@ public final class StrictMode { /** @hide */ @TestApi public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy + /** @hide */ + @TestApi public static final int DETECT_VM_NON_SDK_API_USAGE = 0x40 << 24; // for VmPolicy + private static final int ALL_VM_DETECT_BITS = DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS @@ -276,7 +281,9 @@ public final class StrictMode { | DETECT_VM_FILE_URI_EXPOSURE | DETECT_VM_CLEARTEXT_NETWORK | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION - | DETECT_VM_UNTAGGED_SOCKET; + | DETECT_VM_UNTAGGED_SOCKET + | DETECT_VM_NON_SDK_API_USAGE; + // Byte 3: Penalty @@ -418,6 +425,13 @@ public final class StrictMode { */ private static final AtomicInteger sDropboxCallsInFlight = new AtomicInteger(0); + /** + * Callback supplied to dalvik / libcore to get informed of usages of java API that are not + * a part of the public SDK. + */ + private static final Consumer sNonSdkApiUsageConsumer = + message -> onVmPolicyViolation(new NonSdkApiUsedViolation(message)); + private StrictMode() {} /** @@ -823,6 +837,23 @@ public final class StrictMode { return disable(DETECT_VM_ACTIVITY_LEAKS); } + /** + * Detect reflective usage of APIs that are not part of the public Android SDK. + */ + public Builder detectNonSdkApiUsage() { + return enable(DETECT_VM_NON_SDK_API_USAGE); + } + + /** + * Permit reflective usage of APIs that are not part of the public Android SDK. Note + * that this only affects {@code StrictMode}, the underlying runtime may + * continue to restrict or warn on access to methods that are not part of the + * public SDK. + */ + public Builder permitNonSdkApiUsage() { + return disable(DETECT_VM_NON_SDK_API_USAGE); + } + /** * Detect everything that's potentially suspect. * @@ -854,6 +885,8 @@ public final class StrictMode { detectContentUriWithoutPermission(); detectUntaggedSockets(); } + + // TODO: Decide whether to detect non SDK API usage beyond a certain API level. return this; } @@ -1887,6 +1920,13 @@ public final class StrictMode { } else if (networkPolicy != NETWORK_POLICY_ACCEPT) { Log.w(TAG, "Dropping requested network policy due to missing service!"); } + + + if ((sVmPolicy.mask & DETECT_VM_NON_SDK_API_USAGE) != 0) { + VMRuntime.setNonSdkApiUsageConsumer(sNonSdkApiUsageConsumer); + } else { + VMRuntime.setNonSdkApiUsageConsumer(null); + } } } @@ -2617,6 +2657,8 @@ public final class StrictMode { return DETECT_VM_UNTAGGED_SOCKET; } else if (mViolation instanceof ExplicitGcViolation) { return DETECT_EXPLICIT_GC; + } else if (mViolation instanceof NonSdkApiUsedViolation) { + return DETECT_VM_NON_SDK_API_USAGE; } throw new IllegalStateException("missing violation bit"); } diff --git a/core/java/android/os/strictmode/NonSdkApiUsedViolation.java b/core/java/android/os/strictmode/NonSdkApiUsedViolation.java new file mode 100644 index 0000000000000..2f0cb50cdfc4c --- /dev/null +++ b/core/java/android/os/strictmode/NonSdkApiUsedViolation.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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.os.strictmode; + +/** + * Subclass of {@code Violation} that is used when a process accesses + * a non SDK API. + */ +public final class NonSdkApiUsedViolation extends Violation { + /** @hide */ + public NonSdkApiUsedViolation(String message) { + super(message); + } +}