【framework】framework中為systemserver新增許可權
之前以為在framework中不需要申請許可權就可以直接使用,直到最近移植android6.0時,發現原來4.4上的程式碼移植到6.0上後無法正常使用,排查原因發現是在讀寫sdcard時因為沒有讀寫許可權導致出錯,這才直到原來framework中的服務也是需要配置許可權相關的東西的,只是方法和app中配置的方法不一樣。如下記錄該問題解決的方法:
1、測試程式碼
我在system server中自定義的服務中加入一段讀寫外接儲存的測試程式碼,程式碼實現的功能非常簡單,主要用三個方法構成,一個用於檢測外接儲存裝置的掛載狀態,一個用於讀取顯示外接儲存中的檔案列表,第三個方法用於向外接儲存裝置中建立一個測試檔案,建立前如果存在就先刪除。
private final static String[] sStorageArray = { "/mnt/extsd",
"/mnt/extsd2", "/mnt/usbhost/Storage01", "/mnt/usbhost/Storage02",
"/mnt/usbhost/Storage03" };
@RequiresPermission(anyOf = {"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"})
private static void checkStorageState() {
String state = Environment.getExtsdStorageState();
Log.d(TAG, "getExtsdStorageState=" + state);
state = Environment.getExtsd2StorageState();
Log.d(TAG, "getExtsd2StorageState=" + state);
state = Environment.getUsbStorageState();
Log.d(TAG, "getUsbStorageState=" + state);
state = Environment.getExtsd2StorageState();
Log.d(TAG, "getExtsd2StorageState=" + state);
}
@RequiresPermission(anyOf = {"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"})
private static void listFile(final String home) {
Log.d(TAG, "Home ="+home);
File f = new File(home);
if (null != f && f.exists()) {
Log.d(TAG, "Home " + home + " is avaiable!");
File list[] = f.listFiles();
if (null != list && 0 < list.length) {
Log.d(TAG, "File list is not empty.");
for (File tf : list) {
if (null != tf) {
Log.d(TAG, "File name=" + tf.getName());
}
}
}
else {
Log.e(TAG, "File list is empty.");
}
} else {
Log.e(TAG, "Home " + home + " is not avaiable.");
}
}
@RequiresPermission(anyOf = {"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"})
private static void writeFile(final String home) {
Log.d(TAG, "Home ="+home);
File f = new File(home);
if (null != f && f.exists()) {
Log.d(TAG, "Home " + home + " is avaiable!");
final String fname = new StringBuilder().append(home).append(File.separatorChar).append("test.file").toString();
File tf = new File(fname);
try {
tf.deleteOnExit();
tf.createNewFile();
Log.d(TAG, "Create "+fname+" success!");
} catch (IOException e) {
Log.e(TAG, "Write file:"+fname+" failed.");
e.printStackTrace();
}
} else {
Log.e(TAG, "Home " + home + " is not avaiable.");
}
}
2、問題描述
執行上述的測試程式碼後,發現獲取儲存裝置狀態成功,但是讀取裝置列表時始終為null,而建立檔案時則直接丟擲異常,異常原因是無許可權。報錯的主要日誌如下:
01-01 08:00:50.661 E/UpdateManagerService( 2591): Write file:/mnt/usbhost/Storage02/test.file failed.
01-01 08:00:50.661 W/System.err( 2591): java.io.IOException: open failed: EACCES (Permission denied)
01-01 08:00:50.665 W/System.err( 2591): at java.io.File.createNewFile(File.java:939)
01-01 08:00:50.665 W/System.err( 2591): at com.android.server.update.UpdateManagerService.writeFile(UpdateManagerService.java:77)
01-01 08:00:50.665 W/System.err( 2591): at com.android.server.update.UpdateManagerService.-wrap2(UpdateManagerService.java)
01-01 08:00:50.665 W/System.err( 2591): at com.android.server.update.UpdateManagerService$Lifecycle$1.run(UpdateManagerService.java:119)
01-01 08:00:50.665 W/System.err( 2591): at java.lang.Thread.run(Thread.java:818)
01-01 08:00:50.665 W/System.err( 2591): Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
01-01 08:00:50.669 W/System.err( 2591): at libcore.io.Posix.open(Native Method)
01-01 08:00:50.670 W/System.err( 2591): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
01-01 08:00:50.670 W/System.err( 2591): at java.io.File.createNewFile(File.java:932)
01-01 08:00:50.670 W/System.err( 2591): ... 4 more
3、問題分析
(1)、檢視當前程式所屬的使用者組
通過上述錯誤日誌,找到對應的程式號,如本例中的程式號為2591。進入/proc虛擬檔案系統下程式的相關目錄,檢視程式的執行資訊,如本例中的程式目錄:
cd /proc/2951
通過如下命令檢視程式的資訊:
cat status
程式資訊中有一個Groups屬性,包含了當前程式所屬的使用者組,該程式僅僅擁有所屬組所具備的許可權。
上面的裡面是我修改過具備讀寫外接儲存裝置後的status,修改之前Groups中不包含1015組。
(2)、檢視所屬使用者組具備的許可權
上一步得到的使用者組都是int型,其定義在android/system/core/include/private/android_filesystem_config.h檔案中,本文列出其中部分定義說明,具體的可以自行查閱相關程式碼。從程式碼中可以看到外接儲存卡寫許可權屬於AID_SDCARD_RW組,即1015(上面說過,我在修改前system_server是不具備1015的使用者組的,所以導致讀寫外接儲存卡時丟擲了許可權問題)。
/* This is the master Users and Groups config for the platform.
* DO NOT EVER RENUMBER
*/
#define AID_ROOT 0 /* traditional unix root user */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define AID_ADB 1011 /* android debug bridge (adbd) */
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
#define AID_SDCARD_RW 1015 /* external storage write access */
#define AID_VPN 1016 /* vpn system */
#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
#define AID_GPS 1021 /* GPS daemon */
#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
#define AID_MEDIA_RW 1023 /* internal media storage write access */
#define AID_MTP 1024 /* MTP USB driver access */
#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
#define AID_DRMRPC 1026 /* group for drm rpc */
#define AID_NFC 1027 /* nfc subsystem */
#define AID_SDCARD_R 1028 /* external storage read access */
#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_LOOP_RADIO 1030 /* loop radio devices */
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
#define AID_PACKAGE_INFO 1032 /* access to installed package details */
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources */
/* The range 2900-2999 is reserved for OEM, and must never be
* used here */
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 2999
/* The 3000 series are intended for use as supplemental group id's only.
* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
#define AID_APP 10000 /* first app user */
#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
#define AID_USER 100000 /* offset for uid ranges for each user */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */
(3)、檢視system_server啟動引數
system_server是由ZygoteInit類負責初始化和啟動的,相關的程式碼在sdk的android/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java檔案中。其中關鍵的啟動程式碼如下。從程式碼中可以看到,在啟動sysetm_server時通過--setgroups為其設定了所屬使用者組。
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1015,1018,1021,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs);
}
return true;
}
注意:上述程式碼已經是我修改後(即新增使用者組1015後)的程式碼,此時編譯的system_server已經具備了讀寫外接儲存的許可權。4、解決方法
在第三步的“問題分析”的最中其實已經給出瞭解決辦法,但是這裡還是重新說明下。問題總結主要幾個方面:
(1)、檢視程式當前所屬的組;
(2)、檢視所需許可權所屬的組;
(3)、比對當前程式是否屬於需要許可權的組;
(4)、修改啟動引數新增組;
故,本文最後修改了ZygoteInit.java類,然後在--setgroups引數中增加了1015使用者組。
相關文章
- Django REST framework API 指南(14):許可權DjangoRESTFrameworkAPI
- Django REST framework中認證和許可權的使用方法DjangoRESTFramework
- Django-Rest-Framework 許可權管理原始碼淺析DjangoRESTFramework原始碼
- django-rest-framework 基礎三 認證、許可權和頻率DjangoRESTFramework
- .NET Framework (最新版本到.NET Framework 4.7.2)中的新增功能Framework
- framework——View新增過程FrameworkView
- Django框架rest_framework中APIView的as_view()原始碼解析、認證、許可權、頻率控制Django框架RESTFrameworkAPIView原始碼
- django-rest-framework-原始碼解析004-三大驗證(認證/許可權/限流)DjangoRESTFramework原始碼
- Android Framework中的Application Framework層介紹AndroidFrameworkAPP
- Android property屬性許可權新增Android
- Ubuntu-給新增使用者新增root許可權Ubuntu
- 許可權之選單許可權
- linux 檔案許可權 s 許可權和 t 許可權解析Linux
- Entity Framework Core 2.1,新增種子資料Framework
- 如何用 Vue 實現前端許可權控制(路由許可權 + 檢視許可權 + 請求許可權)Vue前端路由
- 許可權系統:一文搞懂功能許可權、資料許可權
- Linux 中的許可權管理Linux
- ABP Framework V4.4 RC 新增功能介紹Framework
- 訪問framework中hide方法FrameworkIDE
- 為什麼許可權授權很難?- osohq
- Android FrameworkAndroidFramework
- 使用 Pyinstaller 打包為 windows exe程式 新增管理員許可權的多種方式Windows
- Linux特殊許可權之suid、sgid、sbit許可權LinuxUI
- 如何優雅的在 vue 中新增許可權控制Vue
- MySQL 給使用者新增 ALTER VIEW 的許可權MySqlView
- mysql8.0新增使用者,並指定許可權MySql
- 給非 root 使用者新增 docker 使用許可權Docker
- 給安卓 app 新增許可權的一種方法安卓APP
- mysql 新增、刪除使用者和許可權分配MySql
- Android 中的危險許可權Android
- Linux中檔案的許可權Linux
- Linux中的許可權機制Linux
- mysql許可權MySql
- 許可權控制
- Linux許可權Linux
- android原始碼framework下新增新資源的方法Android原始碼Framework
- ABP Framework 5.2 RC 釋出及新增功能介紹Framework
- 【C# .Net Framework】在.Net Framework中使用gRPCC#FrameworkRPC
- Django REST Framework中的Serializer relationsDjangoRESTFramework