What does @hide mean in the Android source code?
Android has two types of APIs that are not accessible via SDK.
The first one is located in package com.android.internal
. The second API type is a collection of classes and methods that are marked with the @hide Javadoc attribute.
Starting from Android 9 (API level 28), Google 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.
But before API level 28, the hidden methods could still be accessed via Java reflection. The @hide
attribute is just part of Javadoc (droiddoc also), so the @hide
just simply means the method/class/field is excluded from the API docs.
For example, the checkUidPermission()
method in ActivityManager.java
uses @hide
:
/** @hide */
public static int checkUidPermission(String permission, int uid) {
try {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
// Should never happen, but if it does... deny!
Slog.e(TAG, "PackageManager is dead?!?", e);
}
return PackageManager.PERMISSION_DENIED;
}
However, we can call it by reflection:
Class c;
c = Class.forName("android.app.ActivityManager");
Method m = c.getMethod("checkUidPermission", new Class[] {String.class, int.class});
Object o = m.invoke(null, new Object[]{"android.permission.READ_CONTACTS", 10010});
What exactly does Android's @hide annotation do?
What exactly does this do?
It controls what is in the android.jar
that you are compiling against.
When you have, say, compileSdkVersion 19
in your build.gradle
file, what is really happening is that $ANDROID_SDK/platforms/android-19/android.jar
is being added to your compile-time classpath.
That JAR is created as part of compiling Android itself. The Android framework classes are analyzed, and a copy of them is created. This copy:
Strips out all classes, methods, fields, etc. marked with
@hide
Has stub implementations of all the methods that remain (literally
throw new RuntimeException("Stub!")
, the last time I looked)Retains the JavaDoc comments for everything that remains
The JavaDocs are built off of this source tree (which is why the JavaDocs do not show hidden methods), and the SDK edition of the framework JAR is compiled off of this source tree.
but that you can use reflection to access them
That is because, at runtime, the real framework JAR is in your runtime classpath, compiled off of the real source for the framework classes. It contains everything that was marked with @hide
and was stripped out of the compile-time framework JAR.
I can still call some @hide methods (maybe just static ones?) and the app compiles and runs fine as far as I can tell. I just get a lint error
As Karakuri noted, that sure looks like a compile error to me. If I try your code in a compileSdkVersion 22
project, I get a compile error. And when I go to run it, I get:
/tmp/MyApplication/app/src/main/java/com/commonsware/myapplication/MainActivity.java
Error:(16, 23) error: cannot find symbol method isEmailAddress(String)
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.
Information:BUILD FAILED
Now, you can compile against methods that were formerly marked with @hide
, because they were un-hidden in a later Android SDK, and your compileSdkVersion
is on that API level or higher. Using those methods on API levels prior to when they were officially added to the SDK is risky.
I don't care about the possibility of the API being changed
You should, unless you are building only for one device where you control the firmware, including all OS updates. And, in that case, you are probably building your own firmware, and so you can build your own SDK framework JAR from your Android fork, where you remove @hide
from the things you want to really use.
Also if there's any way to disable the lint on a case-by-case basis that would be helpful.
Based on what I see from your screenshot and my PC, that is a compile error from the IDE. You cannot disable compile errors.
Hide a library source code
Android Studio replaces the actual code with something like /* compiled code */
only if you don't have the actual source code for the library and the decompiler isn't activated. But it's trivial to either attach the source code or to install a decompiler.
You can display the bytecode of any class using javap
. See Is it possible to view bytecode of Class file? for details.
Back to your original question: No, it's not possible to actually hide your code because the code is required to actually execute it. And if the code is there you can see the bytecode and decompile it. The best option you have is to obfuscate the code using Proguard which won't get you very far either regarding hiding your code. See How to avoid reverse engineering of an APK file? and Android ProGuard how to hide/obfuscate source code of exported library.
What's the meaning of new @SystemApi annotation, any difference from @hide?
Methods annotated with @SystemApi are a subset of ones with @hide.
It's apparently an indicator for internal teams (perhaps also partners) that these methods are actual APIs, although not for public developers.
As a result, @SystemApi methods will be more stable than @hide ones, which could be changed at any time in the future without any compatibility consideration, and also any OEM is allowed to change them at their own will.
If you are trying to invoke internal APIs via reflection, always prefer @SystemApi methods for better future compatibility.
Cannot find symbol method setDropDownAnimationStyle(int) in AutoCompleteTextView
The method you are trying to use is marked as hidden (pending API council approval). That is why you can not use it.
/**
* <p>Sets the animation style of the auto-complete drop-down list.</p>
*
* <p>If the drop-down is showing, calling this method will take effect only
* the next time the drop-down is shown.</p>
*
* @param animationStyle animation style to use when the drop-down appears
* and disappears. Set to -1 for the default animation, 0 for no
* animation, or a resource identifier for an explicit animation.
*
* @hide Pending API council approval
*/
- See this question for info on @hide. It describes a way to use the method, but that is strongly advised against.
- Official documentation for
AutoCompleteTextView
.
How was the source code of startService() modified to recognize if it was called from background?
Following this link into Android's soure code we find getAppStartModeLocked()
:
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
UidRecord uidRec = mActiveUids.get(uid);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+ packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
+ (uidRec != null ? uidRec.idle : false));
if (uidRec == null || alwaysRestrict || uidRec.idle) {
boolean ephemeral;
if (uidRec == null) {
ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
UserHandle.getUserId(uid), packageName);
} else {
ephemeral = uidRec.ephemeral;
}
if (ephemeral) {
// We are hard-core about ephemeral apps not running in the background.
return ActivityManager.APP_START_MODE_DISABLED;
} else {
if (disabledOnly) {
// The caller is only interested in whether app starts are completely
// disabled for the given package (that is, it is an instant app). So
// we don't need to go further, which is all just seeing if we should
// apply a "delayed" mode for a regular app.
return ActivityManager.APP_START_MODE_NORMAL;
}
final int startMode = (alwaysRestrict)
? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
: appServicesRestrictedInBackgroundLocked(uid, packageName,
packageTargetSdk);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid
+ " pkg=" + packageName + " startMode=" + startMode
+ " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid));
if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
// This is an old app that has been forced into a "compatible as possible"
// mode of background check. To increase compatibility, we will allow other
// foreground apps to cause its services to start.
if (callingPid >= 0) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(callingPid);
}
if (proc != null &&
!ActivityManager.isProcStateBackground(proc.curProcState)) {
// Whoever is instigating this is in the foreground, so we will allow it
// to go through.
return ActivityManager.APP_START_MODE_NORMAL;
}
}
}
return startMode;
}
}
return ActivityManager.APP_START_MODE_NORMAL;
}
And the method appRestrictedInBackgroundLocked()
(which is also called from appServicesRestrictedInBackgroundLocked()
as fallback) decides about the startMode
:
// Unified app-op and target sdk check
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
if (packageTargetSdk >= Build.VERSION_CODES.O) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
}
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
// ...and legacy apps get an AppOp check
int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
uid, packageName);
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
}
switch (appop) {
case AppOpsManager.MODE_ALLOWED:
return ActivityManager.APP_START_MODE_NORMAL;
case AppOpsManager.MODE_IGNORED:
return ActivityManager.APP_START_MODE_DELAYED;
default:
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
}
But the final decision about foreground or background is done in ActivityManager.isProcStateBackground(uidRec.setProcState)
:
/** @hide Should this process state be considered a background state? */
public static final boolean isProcStateBackground(int procState) {
return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
}
So, this section of the first method here gets the current state of foreground or background:
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(callingPid);
}
Related Topics
How to Read Contacts on Android 2.0
How to Implement Onfragmentinteractionlistener
Background Task, Progress Dialog, Orientation Change - Is There Any 100% Working Solution
This Handler Class Should Be Static or Leaks Might Occur: Incominghandler
Run/Install/Debug Android Applications Over Wi-Fi
How to Check Programmatically If an Application Is Installed or Not in Android
Getapplication() Vs. Getapplicationcontext()
How to Assign an Id to a View Programmatically
Install_Failed_No_Matching_Abis When Install Apk
How to Create a Circular Imageview in Android
How to Pass Data Between Fragments
"Debug Certificate Expired" Error in Eclipse Android Plugins
Onsaveinstancestate () and Onrestoreinstancestate ()
Firebase Android: Make Username Unique
Filter Logcat to Get Only the Messages from My Application in Android