content命令操作ContentProvider時報SecurityException: Failed to find PID

目錄

問題描述

分析思路

原因

解決方法


 

問題描述

近日公司之前實現的自定義ContentProvider 在Android8上用content 命令操作時會報錯:

在用content query 時 會是在調用setNotificationUri 的地方出錯。

在用content update時 會是在調用notifyChange的地方出錯。


DatabaseUtils: java.lang.SecurityException: Failed to find PID

 

分析思路

經過分析,得知報錯點在ActivityManagerService.java 中的 checkContentProviderAccess 函數中,

2962應該是輸入命令時命令所在的進程PID,最開始以爲是用命令時,傳進去的是命令所在進程的PID,而命令發送後進程退出找不到進程導致。看log也很符合。於是想着把自研應用MyContentProvider 放到系統進程中去,但有個疑惑的地方是MyContentProvider 所在的進程483 已經是system_server。爲什麼AMS裏面不去找483進程呢?

難道是content 命令在高版本中用不了了?如果是這樣的話這個命令不就用不了了,爲何還要保留呢?於是用命令去查看SettingsProvider 是否能用。

結果發現用settings put global wifi_on 1能修改數據庫,切不會報錯。content update --uri content://settings/global/wifi_on --bind value:s:1 缺改不了數據庫。發現用content update命令時在

isKeyValid 這裏會返回去,後面不會再操作數據庫了。

於是強制把這行屏蔽,讓其能繼續運行下去。缺發現操作settingsProvider時獲取到的pid是system_server進程(這裏由於重啓過,進程號變爲480了)

原因

這就尷尬了,爲何settingsProvider和自定義的Provider傳過去的PID不一致呢?最開始還以爲是哪些配置沒搞好,測了大半天。我一直是覺得Android源碼是不會有問題的,另一方面也覺得分析源碼很麻煩很耗時。後來下定決心想去研究下Binder.getCallingPid ,看是哪裏出問題了。後來在https://blog.csdn.net/bbmcdull/article/details/52046690 這篇博客中找到了答案。

SettingsProvider中調用notifyChange 是通過綁定的handler處理的,傳遞的就是settingsProvider自身的PID,即system_server 故不會出問題。而MyContentProvider 中調用notifyChange 是直接在複寫的update方法中調用的,那麼傳過去的進程就會是content 所在命令的進程。就會報上面這個錯!

 

解決方法

那麼至此也就找到解決方法了:

方法一、參照SettingsProvider 的方式調用notifyChange時,用個綁定新線程的handler去處理,

方法二、

在notifyChange 函數前後分別加上Binder.clearCallingIdentity(); 和Binder.restoreCallingIdentity(origId); 就可以了。

 

對於setNotificationUri 的處理方法也是一樣的!

以後遇到問題,還是不能慫,不能害怕,多分析源碼纔好!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章