Android 9 (API level 28) 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 9 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 debuggable app on a device or emulator running Android 9. The system prints logs if your app accesses certain non-SDK interfaces. If your app calls a "blacklisted" non-SDK interface, the system also throws an error.
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 9, but to which we don't 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.
Some APIs are on a "blacklist", stricter than the greylisted methods. Blacklisted methods cause apps to throw exceptions as shown in the table in Results of keeping non-SDK interfaces.
Android 9 supports detection of non-SDK interface usage using the
API. Please use
to enable this. You can receive a callback for each such usage by using
penaltyListener, where you can implement custom handling. The
object provided in the callback derives from
Throwable, and the enclosed
stack trace provides the context of the usage.
You can also run a static analysis tool veridex on your APK, which covers all code base of the APK including the third-party libraries it integrates, and tries to find uses of hidden APIs.
Limitations of the veridex tool include the following:
- It can't detect invocations through JNI.
- It can detect only a subset of invocations through reflection.
- Its analysis for inactive code paths is limited to API level checks.
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|
Requesting a new public API
If you cannot find an alternative to using a non-SDK interface for a feature in your app, you can file a feature request for a new public API to be added to the SDK.
When making a feature request, please provide as much detail as possible:
- Which greylisted API(s) you are using currently, including the full
descriptor seen in the
Accessing hidden ...logcat message.
- Why you need to use these APIs, including details about the high-level feature that it is necessary for, not just low level details.
- Why any related public SDK APIs are insufficient for your purposes.
- Any other alternatives you have tried, and why these didn't work out.
Giving more information about why you need the new API and why you need the functionality will increase the likelihood of a new public API being granted.
What are non-SDK interfaces?
They are Java fields and methods that are not part of the official Android SDK. They are implementation details that are subject to change without notice.
What is happening in Android 9?
We are setting up restrictions on the use of non-SDK interfaces. The form of these restrictions vary (see How can I detect non-SDK interface uses when my app is running?), but can affect the behavior of your application if you are using non-SDK interfaces.
If I currently use a non-SDK interface, where should I request it?
Please file a Feature Request, and provide detailed info about your use case.
What are the different lists for restricting non-SDK interfaces, and what are their corresponding meaning in terms of restrictive behavior?
Below are the types of lists:
- whitelist: the SDK
- light-greylist: non SDK methods / fields that are still accessible.
- For apps whose target SDK is below API level 28: each use of a dark greylist interface is permitted.
- For apps whose target SDK is API level 28 or higher: same behavior as blacklist
- blacklist: restricted regardless of target SDK. The platform will behave as if the interface is absent. For example, it will throw
NoSuchFieldExceptionwhenever the app is trying to use it, and will not include it when the app wants to know the list of fields/methods of a particular class.
How can I detect non-SDK interface uses when my app is running?
Please build a
app and run your tests, a logcat warning is printed of the form
Accessing hidden field|method ... for every use of non-SDK interfaces,
including that are denied.
How can Google be sure they will capture the needs of all apps through the issuetracker?
We initially seeded the list through static analysis of apps which we have supplemented with:
- manual testing of top Play and non Play apps
- internal reports
- automatic data collection from internal users
- developer preview reports
- additional static analysis designed to conservatively include more false positives
How can I enable access to non-SDK APIs?
Enabling access to non-SDK APIs is possible on development devices using adb.
If you want to see API access information in adb logcat output, you can change the API enforcement policy:
adb shell settings put global hidden_api_policy_pre_p_apps 1 adb shell settings put global hidden_api_policy_p_apps 1
To reset this to the default setting:
adb shell settings delete global hidden_api_policy_pre_p_apps adb shell settings delete global hidden_api_policy_p_apps
These commands do not require a rooted device.
The meaning of the integer given is:
- 0: Disable non-SDK API usage detection. This will also disable logging, and also break the strict mode API, detectNonSdkApiUsage(). Not recommended.
- 1: "Just warn" - permit access to all non-SDK APIs, but keep warnings in the log. The strict mode API will keep working.
- 2: Disallow usage of dark grey and black listed APIs.
- 3: Disallow usage of blacklisted APIs, but allow usage of dark grey listed APIs.
About the API lists
What does the dark grey list in the Android 9 release build contain?
The dark grey list contains methods / fields we haven’t seen being used during our development period, but that we may have missed. The methods / fields that are selected to be in the dark grey list are the ones closely related to the public interfaces in the SDK and the light grey list.
Where are the greylists / blacklist located?
They are built as part of the platform. You can find prebuilt entries here:
- platform/prebuilts/runtime/appcompat/hiddenapi-light-greylist.txt: AOSP list of light grey APIs
- platform/prebuilts/runtime/appcompat/hiddenapi-dark-greylist.txt: AOSP list of dark grey APIs
Additionally, this list contains the SDK 28 list of light grey APIs.
The blacklist and dark grey list are build time derived. We’ve added a build rule that generates the lists on AOSP. It's not the same as the blacklist in P, but the overlap is reasonably good. A developer can download AOSP and then generate the blacklist with the following command:
And then they will find the file in:
What is the approximate size of these lists?
The lists are approximately:
- whitelist (also known as SDK) ~= 74,000 methods and fields
- light-greylist ~= 11,000 methods and fields
- dark-greylist ~= 121,000 methods and fields
- blacklist ~= 9,000 methods and fields
Where can I find the blacklist / greylists in the system image?
They are encoded in the field and method access flag bits in platform dex files. There is no separate file in the system image that contains these lists.
Are the blacklist / greylists the same on different OEM devices with the same Android versions?
Yes OEMs can add their own apis to the blacklist, but cannot remove things from the original/AOSP black or grey lists. The CDD prevents such changes and CTS tests ensure that the Android Runtime is enforcing the list.
Related App compatibility questions
Is there any restriction on non-NDK interfaces in native code?
SDK covers the Java language. For the NDK for native C/C++ code, we did this in Android Nougat. See: Improving Stability with Private C/C++ Symbol Restrictions in Android N
Is there any plan to restrict dex2oat or dex file manipulation?
We don’t have active plans to restrict access to the dex2oat binary, but we do not intend for the dex file format to be stable or a public interface beyond the portions that are publicly specified in the Dalvik Executable format. We reserve the right to modify or eliminate dex2oat and the unspecified portions of the dex format at any time. Please also note that derived files produced by dex2oat such as odex (also known as oat), vdex, cdex are all unspecified formats.
What if a crucial 3p SDK (in particular, an obfuscator) cannot prevent using non-SDK interfaces, but does commit to maintain compatibility with future Android versions? Can Android waive its warnings?
We do not have plans to waive compatibility requirements on a per-SDK basis. If an SDK partner feels that they are unable to maintain compatibility with the current whitelist + greylist API set, they should file a bug requesting the non- SDK methods they will need.
Does the non-SDK interfaces restrictions apply to all apps including system and first-party apps, not just third-party apps?
Yes, however, we exempt apps signed with the platform key, and we also have a
package whitelist for some system image apps. Note that these exemptions only
apply to apps that are in the system image (or updated system image apps).
The list is intended only for apps that build against the private platform APIs,
rather than the SDK APIs (i.e.
LOCAL_PRIVATE_PLATFORM_APIS := true).
Some developers have posted the private API restrictions mechanism and bypassing techniques. What do you comment on it? Will you make the restrictions even harder?
We're aware of the potential workarounds. The good thing is most apps are sticking to public APIs. While we try to make it harder to invoke non-SDK interfaces to ensure compatibility, we need to balance this with keeping the runtime easy to debug. We'll continue to evaluate underlying implementation and work with developers.