问题:应用在AndroidManifest.xml 文件 申请WRITE_EXTERNAL_STORAGE 权限即可对sdcard 下文件进行操作。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
应用的用户id 和所属组是什么?
adb shell 查看 sdcard 文件读写执行权限:
dengpei@dengpei-pc:~$ adb shell
# cd /mnt/sdcard
# ls -al |grep "fileForTestRight.txt"
----rwxr-x 1 system sdcard_rw 0 Jan 18 11:20 fileForTestRight.txt
# whoami
root
#
文件
fileForTestRight.txt
权限:
system --x
sdcard_r rwx
other r_x
sdcrad 文件 权限定义由VoId 设置
gingerbread/system/vold/Volume.cpp
:
int Volume::mountVol() {
dev_t deviceNodes[4];
int n, i, rc = 0;
char errmsg[255];
if (getState() == Volume::State_NoMedia) {
snprintf(errmsg, sizeof(errmsg),
"Volume %s %s mount failed - no media",
getLabel(), getMountpoint());
mVm->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeMountFailedNoMedia,
errmsg, false);
errno = ENODEV;
return -1;
} else if (getState() != Volume::State_Idle) {
errno = EBUSY;
return -1;
}
if (isMountpointMounted(getMountpoint())) {
SLOGW("Volume is idle but appears to be mounted - fixing");
setState(Volume::State_Mounted);
// mCurrentlyMountedKdev = XXX
return 0;
}
n = getDeviceNodes((dev_t *) &deviceNodes, 4);
if (!n) {
SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
return -1;
}
for (i = 0; i < n; i++) {
char devicePath[255];
sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
MINOR(deviceNodes[i]));
SLOGI("%s being considered for volume %s\n", devicePath, getLabel());
errno = 0;
setState(Volume::State_Checking);
if (Fat::check(devicePath)) {
if (errno == ENODATA) {
SLOGW("%s does not contain a FAT filesystem\n", devicePath);
continue;
}
errno = EIO;
/* Badness - abort the mount */
SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
setState(Volume::State_Idle);
return -1;
}
/*
* Mount the device on our internal staging mountpoint so we can
* muck with it before exposing it to non priviledged users.
*/
errno = 0;
if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false,
1000, 1015, 0702, true)) {
SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
continue;
}
SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());
protectFromAutorunStupidity();
if (createBindMounts()) {
SLOGE("Failed to create bindmounts (%s)", strerror(errno));
umount("/mnt/secure/staging");
setState(Volume::State_Idle);
return -1;
}
/*
* Now that the bindmount trickery is done, atomically move the
* whole subtree to expose it to non priviledged users.
*/
if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
SLOGE("Failed to move mount (%s)", strerror(errno));
umount("/mnt/secure/staging");
setState(Volume::State_Idle);
return -1;
}
setState(Volume::State_Mounted);
mCurrentlyMountedKdev = deviceNodes[i];
return 0;
}
SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
setState(Volume::State_Idle);
return -1;
}
doMount(devicePath, "/mnt/secure/staging", false, false, false,
1000, 1015, 0702, true)
定义 uid 1000 gid 1015 文件读写执行权限 为 0702
即 075 ---rwxr-x
继续查看:
gingerbread/system/core/include/private/android_filesystem_config.h
/* 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_GPS 1021 /* GPS daemon */
#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
#define AID_RFU1 1023 /* RFU */
#define AID_RFU2 1024 /* RFU */
#define AID_NFC 1025 /* nfc subsystem */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources */
/* 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_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
#define AID_APP 10000 /* first app user */
可知
AID_SYSTEM 1000 /* system server */
AID_SDCARD_RW 1015 /* external storage write access */
AID_APP 10000 /* first app user */
每个 apk 安装时 PackageInstaller 都会分配一个 userid
并记录在
# ls
accounts.db packages.xml
appwidgets.xml password.key
batterystats.bin registered_services
called_pre_boots.dat shared_prefs
cameraCalFile.bin sync
confirmed_package_behavior.authz theme
confirmed_package_behavior.log throttle
customized_icons_1 trafficstats.bin
device_policies.xml uiderrors.txt
dropbox usagestats
entropy.dat wallpaper_info.xml
gesture.key wallpapers
packages.list
# pwd
/data/system
#
package.xml中,同时也包含 uses-permission 信息
<package name="com.pathfindeng.test" codePath="/data/app/com.pathfindeng.test-1.apk" nativeLibraryPath="/data/data/com.pathfindeng.test/lib" flags="268435456" ft="134eed493a0" it="134eeba07a2" ut="134eed49801" version="1" userId="10137">
<sigs count="1">
<cert index="34" />
</sigs>
<perms>
<item name="android.permission.WRITE_EXTERNAL_STORAGE" />
</perms>
查看 data/data/app目录
# pwd
/data/data
# cd com.pathfindeng.test
# ls -al
drwxr-x--x 4 app_137 app_137 4096 Jan 18 11:20 .
drwxrwx--x 175 system system 12288 Jan 18 10:51 ..
drwxr-xr-x 2 system system 4096 Jan 18 11:20 lib
drwxrwx--x 2 app_137 app_137 4096 Jan 18 10:51 shared_prefs
# cd shar*
# ls -al
drwxrwx--x 2 app_137 app_137 4096 Jan 18 10:51 .
drwxr-x--x 4 app_137 app_137 4096 Jan 18 11:20 ..
-rw-rw---- 1 app_137 app_137 112 Jan 18 10:51 MODE_APPEND.xml
-rw-rw---- 1 app_137 app_137 113 Jan 18 10:51 MODE_PRIVATE.xml
-rw-rw-r-- 1 app_137 app_137 120 Jan 18 10:51 MODE_WORLD_READABLE.xml
-rw-rw--w- 1 app_137 app_137 121 Jan 18 10:51 MODE_WORLD_WRITEABLE.xml
可以看出应用id 为137 其实为 10137. 及该用户权限,所属组权限。
该应用主要代码,及manifest文件
AppRightActivity.java
package com.pathfindeng.test;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
public class AppRightActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setSharedPreferencesData();
}
public void setSdcardData(){
File sdcard = Environment.getExternalStorageDirectory();
String[] fileNames = sdcard.list();
Log.d("pathfindeng","fileNames.length is "+fileNames.length);
File testRight = new File(sdcard, "fileForTestRight.txt");
if(testRight.exists()){
testRight.delete();
Log.d("pathfindeng","delete file ok");
}else{
try {
testRight.createNewFile();
Log.d("pathfindeng","create file ok");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d("pathfindeng", testRight.canRead()+""+testRight.canWrite()+""+testRight.canExecute());
}
public void setSharedPreferencesData (){
SharedPreferences mSharedPreferences;
Editor mEditor;
//
mSharedPreferences = getSharedPreferences("MODE_PRIVATE",MODE_PRIVATE);
mEditor = mSharedPreferences.edit();
mEditor.putString("right", "MODE_PRIVATE");
mEditor.commit();
//
mSharedPreferences = getSharedPreferences("MODE_WORLD_READABLE",MODE_WORLD_READABLE);
mEditor = mSharedPreferences.edit();
mEditor.putString("right", "MODE_WORLD_READABLE");
mEditor.commit();
//
mSharedPreferences = getSharedPreferences("MODE_WORLD_WRITEABLE",MODE_WORLD_WRITEABLE);
mEditor = mSharedPreferences.edit();
mEditor.putString("right", "MODE_WORLD_WRITEABLE");
mEditor.commit();
//
mSharedPreferences = getSharedPreferences("MODE_APPEND",MODE_APPEND);
mEditor = mSharedPreferences.edit();
mEditor.putString("right", "MODE_APPEND");
mEditor.commit();
}
/* (non-Javadoc)
* @see android.app.Activity#onResume()
*/
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
setSdcardData();
}
/* (non-Javadoc)
* @see android.app.Activity#onDestroy()
*/
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pathfindeng.test"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".AppRightActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
继续查看
/gingerbread/frameworks/base/data/etc/platform.xml
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_rw" />
</permission>
应用申请
WRITE_EXTERNAL_STORAGE权限时
即拥有
sdcard_rw组权限。
所以即可解答开篇提出的问题。