• Android O 移植适配


      Android 奥利奥版本早已来袭, 各个厂商ROM 需要适配, 最近发现信息模块能发送信息,却收不到信息, 刚开始以为是底层的问题,

    随后框架反馈是在接收信息时那边为了Ack,需要将数据插入 raw表, 在插入数据库时有异常:

    0-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: Exception dispatching message
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: java.lang.SecurityException: Failed to find provider raw for user 0; expected to find a valid ContentProvider for this authority
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at android.os.Parcel.readException(Parcel.java:1942)
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at android.os.Parcel.readException(Parcel.java:1888)
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at android.content.IContentService$Stub$Proxy.notifyChange(IContentService.java:802)
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at android.content.ContentResolver.notifyChange(ContentResolver.java:2049)
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at com.android.providers.telephony.SmsProvider.notifyChange(SmsProvider.java:1832)
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at com.android.providers.telephony.SmsProvider.insert(SmsProvider.java:652)
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at android.content.ContentProvider$Transport.insert(ContentProvider.java:271)
    10-23 09:43:35.184 27885 28039 E GsmInboundSmsHandler: at android.content.ContentResolver.insert(ContentResolver.java:1542)

    所以需要应用分析, 刚开始从方法看是notifyChange 时出现问题,通过https://developer.android.com/about/versions/oreo/android-8.0-changes.html?hl=zh-cn

    查询得知:

    Android 8.0 更改了 ContentResolver.notifyChange() 和 registerContentObserver(Uri, boolean, ContentObserver) 在针对 Android 8.0 的应用中的行为方式。

    现在,这些 API 需要在所有 URI 中为颁发机构定义一个有效的 ContentProvider。使用相关权限定义一个有效的 ContentProvider 可帮助您的应用防范来自恶意应用的内容变更,并防止将可能的私密数据泄露给恶意应用。

    但是这个说的很笼统,也没有实例,在网上查询了一下,stackoverFlow上也有类似问题反馈,但是也没找到合适的解决方法。

    正当山穷水尽疑无路之时,突然想起了 read the f**king souce code 这句话,于是使用grok 搜索抛出 SecurityException 这个异常的源码,在ActivityManagerService.java中找到:

    public String checkContentProviderAccess(String authority, int userId) {
    11726 if (userId == UserHandle.USER_ALL) {
    11727 mContext.enforceCallingOrSelfPermission(
    11728 Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
    11729 userId = UserHandle.getCallingUserId();
    11730 }
    11731
    11732 ProviderInfo cpi = null;
    11733 try {
    11734 cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
    11735 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
    11736 | PackageManager.MATCH_DISABLED_COMPONENTS
    11737 | PackageManager.MATCH_DIRECT_BOOT_AWARE
    11738 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
    11739 userId);
    11740 } catch (RemoteException ignored) {
    11741 }
    11742 if (cpi == null) {
    11743 return "Failed to find provider " + authority + " for user " + userId
    11744 + "; expected to find a valid ContentProvider for this authority";
    11745 }
    11746

    最终看到了源码中对于SDK 在大于等于 Android O 的版本中的处理:

    298 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
    299 IContentObserver observer, int userHandle, int targetSdkVersion) {
    300 if (observer == null || uri == null) {
    301 throw new IllegalArgumentException("You must pass a valid uri and observer");
    302 }
    303
    304 final int uid = Binder.getCallingUid();
    305 final int pid = Binder.getCallingPid();
    306
    307 userHandle = handleIncomingUser(uri, pid, uid,
    308 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
    309
    310 final String msg = LocalServices.getService(ActivityManagerInternal.class)
    311 .checkContentProviderAccess(uri.getAuthority(), userHandle);
    312 if (msg != null) {
    313 if (targetSdkVersion >= Build.VERSION_CODES.O) {
    314 throw new SecurityException(msg);
    315 } else {
    316 if (msg.startsWith("Failed to find provider")) {
    317 // Sigh, we need to quietly let apps targeting older API
    318 // levels notify on non-existent providers.
    319 } else {
    320 Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
    321 return;
    322 }
    323 }
    324 }

    从而也明确了 log 中输出的 java.lang.SecurityException: Failed to find provider raw for user 0

    raw 就是 authority ,这样问题就浮出水面了, 系统之所以跑那个异常,是因为找不到对应这种以raw 作为authority的provider, 我们的TelephonyProvider中只有 以 sms mms  sms-mms 作为authority的provider

    所以抛出异常,看到这里我还以为是框架那边在插入时候传入注册监听的registerContentObserver 有问题造成, 所以又想将包袱推给别人,结果框架那边根本就没有注册这种监听,但是对方确给我指明了道路,

    就是框架在插入后,会返回uri, 这个出问题的地方就是notifyChange中使用了 insert 返回的uri, 所以是插入返回uri出现了问题, 最终发现是Provider 返回uri那块没有移植Android O 逻辑:

    if (table == TABLE_SMS) {
    uri = Uri.withAppendedPath(url, "/" + rowID);
    } else {
    uri = Uri.withAppendedPath(url, "/" + table + "/" + rowID );
    }

    OMG, read the souce code is so useful .....

  • 相关阅读:
    获取缓存文件大小并清理 By HL
    iOS 模糊、精确搜索匹配功能方法总结 By HL
    让 iOS 设备 “说出” 你想说的话!! #DF
    自定义索引--秀清
    云端iclound使用-陈棚
    IM开发之Socket通信开源类库CocoaAsyncSocket
    iOS App 架构文章推荐
    IM开发通信协议基础知识(一)---TCP、UDP、HTTP、SOCKET
    [手游项目5]windows获得当前进程名
    【软件安装】c++11安装
  • 原文地址:https://www.cnblogs.com/yangwubo/p/7723639.html
Copyright © 2020-2023  润新知