博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android P @hide API Alert
阅读量:4310 次
发布时间:2019-06-06

本文共 11821 字,大约阅读时间需要 39 分钟。

原文地址:

Detected problems with API compatibility(visit g.co/dev/appcompat for more info)

Recently, the mobile phone has upgraded Android 9. When entering the application, it will pop up a box

Detected problems with API compatibility(visit g.co/dev/appcompat for more info)

I was scared to sweat. I looked at the information on the corresponding website. It turned out that android restricted the use of the hide annotation api. Note that this is not the original hide annotation API in the sdk, but the virtual machine level.

This article is used to record the entire investigation process.

First, the location of the warning pop-up is located in the performRestart function of Activity.java.

7238         // This property is set for all non-user builds except final release7239         boolean isApiWarningEnabled = SystemProperties.getInt("ro.art.hiddenapi.warning", 0) == 1;7240 7241         if (isAppDebuggable || isApiWarningEnabled) {7242             if (!mMainThread.mHiddenApiWarningShown && VMRuntime.getRuntime().hasUsedHiddenApi()) {7243                 // Only show the warning once per process.7244                 mMainThread.mHiddenApiWarningShown = true;7245 7246                 String appName = getApplicationInfo().loadLabel(getPackageManager())7247                         .toString();7248                 String warning = "Detected problems with API compatibility\n"7249                                  + "(visit g.co/dev/appcompat for more info)";7250                 if (isAppDebuggable) {7251                     new AlertDialog.Builder(this)7252                         .setTitle(appName)7253                         .setMessage(warning)7254                         .setPositiveButton(android.R.string.ok, null)7255                         .setCancelable(false)7256                         .show();7257                 } else {7258                     Toast.makeText(this, appName + "\n" + warning, Toast.LENGTH_LONG).show();7259                 }7260             }7261         }
  1. Line 7241 checks to see if the user has invoked the hidden API (@hide annotated api) if the application has debug mode on, or the ro.art.hiddenapi.warning property is 1.
  2. After the previous step, 7241 is checked, provided that the application starts without a warning to invoke the hidden api, and during this time the hidden API is invoked, then the warning pops up.
  3. There are two ways to warn. The first is that the tunable application uses a dialog pop-up warning, or else uses the toast pop-up warning.

After the above analysis, we know the general process.

VMRuntime.getRuntime().hasUsedHiddenApi() is the basis for judging whether an application has called a hidden function.

VMRuntime is the Runtime class in the runtime.cc of the art code when the art virtual machine is running. We know that the call between java and C ++ uses jni as the binder. The corresponding jni code is in art/runtime/native/dalvik_system_VMRuntime.cc, and the function is

static jboolean VMRuntime_hasUsedHiddenApi(JNIEnv*, jobject) {  return Runtime::Current()->HasPendingHiddenApiWarning() ? JNI_TRUE : JNI_FALSE;}

art Runtime is a singleton. We analyze the HasPendingHiddenApiWarning function.

bool HasPendingHiddenApiWarning() const {    return pending_hidden_api_warning_;  }

That is to read the variable value of pending_hidden_api_warning_.

So what we need to focus on is where the value is set.

void SetPendingHiddenApiWarning(bool value) {    pending_hidden_api_warning_ = value;  }

There are three places to call the function, two of which are set to false to indicate that we don't need to care about clearing the variable, so there is only one place in the art/runtime/hidden_api.cc file.

The code we need to care about is as follows.

template
209 Action GetMemberActionImpl(T* member,210 HiddenApiAccessFlags::ApiList api_list,211 Action action,212 AccessMethod access_method)

This is a template function. There are two implementations.

// Need to instantiate this.template Action GetMemberActionImpl
(ArtField* member, HiddenApiAccessFlags::ApiList api_list, Action action, AccessMethod access_method);template Action GetMemberActionImpl
(ArtMethod* member, HiddenApiAccessFlags::ApiList api_list, Action action, AccessMethod access_method);

Before we analyze the GetMemberActionImpl function, let's figure out where to call it, and look through all the code we found in the art/runtime/hidden_api.h file

template
inline Action GetMemberAction(T* member, Thread* self, std::function
fn_caller_is_trusted, AccessMethod access_method) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(member != nullptr); // Decode hidden API access flags. // NB Multiple threads might try to access (and overwrite) these simultaneously, // causing a race. We only do that if access has not been denied, so the race // cannot change Java semantics. We should, however, decode the access flags // once and use it throughout this function, otherwise we may get inconsistent // results, e.g. print whitelist warnings (b/78327881). HiddenApiAccessFlags::ApiList api_list = member->GetHiddenApiAccessFlags(); Action action = GetActionFromAccessFlags(member->GetHiddenApiAccessFlags()); if (action == kAllow) { // Nothing to do. return action; } // Member is hidden. Invoke `fn_caller_in_platform` and find the origin of the access. // This can be *very* expensive. Save it for last. if (fn_caller_is_trusted(self)) { // Caller is trusted. Exit. return kAllow; } // Member is hidden and caller is not in the platform. return detail::GetMemberActionImpl(member, api_list, action, access_method);}

Two parameters api_list and action are validated in the function. The api_list parameter is obtained using the member->GetHiddenApiAccessFlags() function, which is actually an enumeration type, and the code uses the function or variable type, including the following

enum ApiList {
kWhitelist = 0, whitelist function
kLightGreylist, white grey list
kDarkGreylist, grey list
kBlacklist, blacklist
kNoList, not in the list.
};
Action represents the default action performed by different list listings, and is also an enumeration variable.
GetActionFromAccessFlags(member->GetHiddenApiAccessFlags())

enum Action {  kAllow,  //pass  kAllowButWarn,  //Pass but warn  kAllowButWarnAndToast,  //Pass but warn by toast  kDeny  //refuse};inline Action GetActionFromAccessFlags(HiddenApiAccessFlags::ApiList api_list) {  if (api_list == HiddenApiAccessFlags::kWhitelist) {    return kAllow;  //The default action of white list is through.  }//Next, we need to decide how to execute the default action based on EnforcementPolicy.  EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();  if (policy == EnforcementPolicy::kNoChecks) {    // Exit early. Nothing to enforce.    return kAllow;  }  // if policy is "just warn", always warn. We returned above for whitelist APIs.  if (policy == EnforcementPolicy::kJustWarn) {    return kAllowButWarn;  }  DCHECK(policy >= EnforcementPolicy::kDarkGreyAndBlackList);  // The logic below relies on equality of values in the enums EnforcementPolicy and  // HiddenApiAccessFlags::ApiList, and their ordering. Assertions are in hidden_api.cc.  if (static_cast
(policy) > static_cast
(api_list)) { return api_list == HiddenApiAccessFlags::kDarkGreylist ? kAllowButWarnAndToast : kAllowButWarn; } else { return kDeny; }}

After reading the meaning of app_list and action, we return to analyze the GetMemberActionImpl function.

208 template
209 Action GetMemberActionImpl(T* member,210 HiddenApiAccessFlags::ApiList api_list,211 Action action,212 AccessMethod access_method) {213 DCHECK_NE(action, kAllow);214 215 // Get the signature, we need it later.216 MemberSignature member_signature(member);217 218 Runtime* runtime = Runtime::Current();219 220 // Check for an exemption first. Exempted APIs are treated as white list.221 // We only do this if we're about to deny, or if the app is debuggable. This is because:222 // - we only print a warning for light greylist violations for debuggable apps223 // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs.224 // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever225 // possible.226 const bool shouldWarn = kLogAllAccesses || runtime->IsJavaDebuggable();227 if (shouldWarn || action == kDeny) { 228 if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) { //1 for the function in the exempted list, pass directly.229 action = kAllow;230 // Avoid re-examining the exemption list next time.231 // Note this results in no warning for the member, which seems like what one would expect.232 // Exemptions effectively adds new members to the whitelist.233 MaybeWhitelistMember(runtime, member); //Add to white list234 return kAllow;235 }236 237 if (access_method != kNone) {238 // Print a log message with information about this class member access.239 // We do this if we're about to block access, or the app is debuggable.240 member_signature.WarnAboutAccess(access_method, api_list); //2 print log that cannot be passed directly.241 }242 }243 244 if (kIsTargetBuild && !kIsTargetLinux) {245 uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();246 // Assert that RAND_MAX is big enough, to ensure sampling below works as expected.247 static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");248 if (eventLogSampleRate != 0 && //3 some cases print event log. And control the speed.249 (static_cast
(std::rand()) & 0xffff) < eventLogSampleRate) {250 member_signature.LogAccessToEventLog(access_method, action);251 }252 }253 254 if (action == kDeny) { // action is a direct return of refusal.255 // Block access256 return action;257 }258 259 // Allow access to this member but print a warning.260 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);261 262 if (access_method != kNone) { //Print warning263 // Depending on a runtime flag, we might move the member into whitelist and264 // skip the warning the next time the member is accessed.265 MaybeWhitelistMember(runtime, member);266 267 // If this action requires a UI warning, set the appropriate flag.268 if (shouldWarn &&269 (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag())) {270 runtime->SetPendingHiddenApiWarning(true);271 }272 }273 274 return action;275 }

As you can see from the code above, the GetMemberActionImpl function is mainly used to print log and add whitelist for different action.

Thus, the final function is GetActionFromAccessFlags function.

Our problem is generally clear here.

The whole framework is based on a flags in the method to get the corresponding execution action, and there are two more points, where flags are set, and how hidden_api_policy_is set.

 

转载于:https://www.cnblogs.com/kelisi-king/p/10761223.html

你可能感兴趣的文章
NR LTE UMTS GSM CDMA TDS频点频率换算工具
查看>>
servlet基础
查看>>
机房测试8.23
查看>>
thinkphp 迁移数据库 -Phinx 简单说明文档
查看>>
对软件工程的理解
查看>>
下载IDEA并安装scala插件
查看>>
MVC AJAX Pager Helper
查看>>
P1004 方格取数-洛谷luogu-dp动态规划
查看>>
sql存储过程
查看>>
sql注入100种姿势过waf(一):waf 了解
查看>>
Vulnhub靶场渗透练习(三) bulldog
查看>>
软件工程展望
查看>>
AFNetworking实现程序重新启动时的断点续传
查看>>
Java案例整理
查看>>
【python3基础】python3 神坑笔记
查看>>
小椛椛的板子们2
查看>>
元类的三大核心:__new__,__init__和__call__
查看>>
!!在JS中代表什么
查看>>
Oracle 中的sql函数以及分页
查看>>
Android 发送邮件时遭遇 : no object DCH for MIME type multipart/mixed
查看>>