Android P introduces new restrictions on the use of non-SDK interfaces, whether directly, via reflection, or via JNI. These restrictions are applied whenever an app references a non-SDK interface or attempts to obtain its handle using reflection or JNI. For more information about this decision, see Improving Stability by Reducing Usage of non-SDK Interfaces.
In general, apps should only use the officially documented parts of the classes in the SDK. In particular, this means that you should not plan to access methods or fields that are not listed in the SDK when you interact with a class via semantics such as reflection.
Using such methods or fields has a high risk of breaking your app.
Differentiating between SDK and non-SDK interfaces
Generally speaking, SDK interfaces are those ones found documented in the Android framework Package Index. Handling of non-SDK interfaces is an implementation detail that the API abstracts away; it is subject to change without notice.
Android P introduces new restrictions on the use of non-SDK interfaces, whether directly, via reflection, or via JNI. These restrictions are applied whenever an app references a non-SDK interface or attempts to obtain its handle using reflection or JNI.
Testing for non-SDK interfaces
You can test your app by downloading the newest version of the Developer Preview of Android P. The Developer Preview prints logs and potentially displays toasts if your app accesses certain, "greylisted" non-SDK interface. If your app calls a "blacklisted" non-SDK interface, the Developer Preview throws an error.
Pay attention to the toasts, which call attention to interfaces that are proposed for restriction. Also, make sure to inspect your app's log messages, which contain more detailed information about the non-SDK interface that your app accessed, including the declaring class, name, and type in the format used by the Android runtime. Log messages also indicate the means of access: direct, via reflection, or via JNI. Last, log messages show whether the called non-SDK interface belongs to the greylist or the blacklist.
You can use
adb logcat to access these log messages, which
appear under the PID of the running app. For example, an entry in the log
might read as follows:
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
Greylisted non-SDK interfaces encompass methods and fields which continue to function in Android P, but to which we do not guarantee access in future versions of the platform. If there is a reason that you cannot implement an alternative strategy to a greylisted API, you may file a bug to request reconsideration of the restriction.
Developer Preview 2 moves to a blacklist methods that had been part of a second, "dark" greylist in Developer Preview 1. Blacklisted methods cause apps to throw exceptions as shown in the table in Results of keeping non-SDK interfaces.
Developer Preview 2 also adds
StrictMode support for non-SDK interfaces,
detectNonSdkApiUsage, so that when your app calls a greylisted app,
the stack trace shows the context.
Results of keeping non-SDK interfaces
The following table provides details about means of access and their respective results.
|Means of access||Result|
|Dalvik instruction referencing a field||NoSuchFieldError thrown|
|Dalvik instruction referencing a method||NoSuchMethodError thrown|
|Reflection via Class.getDeclaredField() or Class.getField()||NoSuchFieldException thrown|
|Reflection via Class.getDeclaredMethod(), Class.getMethod()||NoSuchMethodException thrown|
|Reflection via Class.getDeclaredFields(), Class.getFields()||Non-SDK members not in results|
|Reflection via Class.getDeclaredMethods(), Class.getMethods()||Non-SDK members not in results|
|JNI via env->GetFieldID()||NULL returned, NoSuchFieldError thrown|
|JNI via env->GetMethodID()||NULL returned, NoSuchMethodError thrown|