转载:
一、init进程启动
init.xxx.rc
#modify by tank
export EXTERNAL_STORAGE /storage/sdcard0
mkdir /data/media 0775 media_rw media_rw
chown media_rw media_rw /data/media
mkdir /storage/sdcard0 0700 system system
mkdir /storage/sdcard1 0700 system system
symlink /storage/sdcard0 /sdcard
symlink /storage/sdcard0 /mnt/sdcard
# sd card mount point
# mkdir /mnt/media_rw/sdcard0 0700 media_rw media_rw
#
# # sd card fuse mount point
# mkdir /mnt/sdcard 0000 system system
# symlink /mnt/sdcard /sdcard
#end tank
# service for sd card access
#service fuse_sdcard0 /system/bin/sdcard -u 1023 -g 1023 -d /mnt/media_rw/sdcard0 /mnt/sdcard
# class core
#modify by tank
# virtual sdcard daemon running as media_rw (1023)
service fuse_sdcard /system/bin/sdcard -u 1023 -g 1023 -d /data/media /storage/sdcard0
class main
#end tank
二、看sdcard进程
sdcard空间不足
struct fuse {
pthread_mutex_t lock;
__u64 next_generation;
int fd;
derive_t derive;
bool split_perms;
gid_t write_gid;
struct node root;
char obbpath[PATH_MAX];
//add by tank
uint64_t free_size;
uint64_t limit_size;
//end tank
Hashmap* package_to_appid;
Hashmap* appid_with_rw;
};
static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
const struct fuse_in_header* hdr, const struct fuse_write_in* req,
const void* buffer)
{
struct fuse_write_out out;
struct handle *h = id_to_ptr(req->fh);
int res;
__u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGESIZE)));
//add by tank for limit write to fuse sdcard when data space not enough
TRACE("fuse->root.name:%s\n",fuse->root.name);
if(!strncmp( fuse->root.name,"/data",strlen("/data"))){
struct statfs stat;
if (statfs(fuse->root.name, &stat) < 0) {
ALOGE("get %s fs status fail \n",fuse->root.name);
fuse->free_size =0;
return -errno;
} else {
pthread_mutex_lock(&fuse->lock);
TRACE("statfs stat.f_bfree: %lld, stat.f_bsize: %d\n", stat.f_bfree, stat.f_bsize);
fuse->free_size = stat.f_bfree*stat.f_bsize;
fuse->limit_size = stat.f_blocks*stat.f_bsize*0.1;//limit size 1/10 of the total size
TRACE("statfs fuse->limit_size: %lld", fuse->limit_size);
pthread_mutex_unlock(&fuse->lock);
}
TRACE("[fuse_debug] fuse.free_size 1 = %lld,root name =%s \n",fuse->free_size,fuse->root.name);
pthread_mutex_lock(&fuse->lock);
fuse->free_size -=req->size;
pthread_mutex_unlock(&fuse->lock);
TRACE("[fuse_debug] fuse.free_size 2 = %lld\n",fuse->free_size);
if(fuse->free_size <= fuse->limit_size ){
errno = ENOSPC;
ERROR("[fuse_debug] Oops fuse.free_size = %ld, less than internal sdcard free size threshold ,no space for write!!!!\n",fuse->free_size);
return -errno;
}
}
//end tank
if (req->flags & O_DIRECT) {
memcpy(aligned_buffer, buffer, req->size);
buffer = (const __u8*) aligned_buffer;
}
TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
h, h->fd, req->size, req->offset);
res = pwrite64(h->fd, buffer, req->size, req->offset);
if (res < 0) {
return -errno;
}
out.size = res;
fuse_reply(fuse, hdr->unique, &out, sizeof(out));
return NO_STATUS;
}
三、MountSerice
frameworks/base/services/core/java/com/android/server/MountService.java
private void readStorageListLocked() {
if (emulated) {
// For devices with emulated storage, we create separate
// volumes for each known user.
mEmulatedTemplate = new StorageVolume(null, descriptionId, true, false, true, mtpReserve, false, maxFileSize, null);
final UserManagerService userManager = UserManagerService.getInstance();
for (UserInfo user : userManager.getUsers(false)) {
createEmulatedVolumeForUserLocked(user.getUserHandle());
}
} else {
// add by tank
if (description == null) {
Slog.e(TAG, "Missing storage path or description in readStorageList");
}
else {
if (primary) {
// do not add a physical primary volume when the external storage is emulated
if (isExternalStorageEmulated()) {
continue;
}
final StorageVolume volume = new StorageVolume(new File(Environment.getExternalStorageDirectory().getPath()),
descriptionId, primary, true, false, mtpReserve,
allowMassStorage, maxFileSize, null);
addVolumeLocked(volume);
if(path != null && path.equals("/storage/sdcard0")){
Slog.d(TAG,"###### TCL fuse sdcard state set ");
mVolumeStates.put(volume.getPath(), Environment.MEDIA_MOUNTED);
} else {
// Until we hear otherwise, treat as unmounted
mVolumeStates.put(volume.getPath(), Environment.MEDIA_UNMOUNTED);
volume.setState(Environment.MEDIA_UNMOUNTED);
}
} else {
mSecondStorageTemplate = new StorageVolume(null, descriptionId, primary, true,
false, mtpReserve, allowMassStorage, maxFileSize, null);
}
}
// end tank
}
}
logcat -s MountService
MountService.java中sd卡路径有如下xml获得:
frameworks/base/core/res/res/xml/storage_list.xml
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<!-- modify by tank storage mount 2015-04-02
<storage android:emulated="true"
android:storageDescription="@string/storage_sd_card" />
<storage android:mountPoint="/mnt/sdcard"
android:storageDescription="@string/storage_sd_card"
android:primary="true" />
-->
<storage android:storageDescription="@string/storage_usb"
android:primary="false" />
<storage
android:mountPoint="/storage/sdcard0"
android:storageDescription="@string/storage_sd_card"
android:removable="false"
android:primary="true"
android:maxFileSize="4096" />
<!--end tank-->
</StorageList>