最近想在安卓手机系统中,对SD卡进行扇区读取,以便进行一些内部操作。经过多次尝试,终于和同事一起解决了这个问题,把心得给大家一起分析下。
首先必须明确一个条件,那就是如果手机系统没有Root过的话,是绝对不可以对磁盘进行扇区级操作的。所以,第一步,请先Root了你的手机或者模拟器吧。
Java语言本身是无法访问磁盘扇区的。所以想借助于Java提供的类库进行操作,此路也不通。
在安卓手机中,所有的硬件设备都是存储于/dev/block目录里,在这个目录你可以看见mmcblk0,mmcblk0p1等等。其中mmcblk0指得是SD卡的本身,mmcblk0p1指的是SD卡的第一个分区所在的位置,熟悉磁盘分区的朋友应该明白这个意思,简单解释就是,磁盘的mbr通过mmcblk0进行访问,而磁盘第一个分区往往开始于第64个扇区,注意,64这个数值是不固定的。也可能是其他值,比如我的SD卡就是129扇区。这数值可以通过解析mbr中的dpt分区表进行得到。
综上可得:在手机中想对SD卡的扇区进行操作,需要完成以下几步:
1、手机Root
2、获得dev/block/mmcblk0和dev/block/mmcblk0p1的访问权限。
3、在Linux系统中编写扇区访问,通过GCC将其进行编译成Java可用的动态链接库文件(linux中以so后缀名结尾)。
贴一个Linux下写的访问扇区的函数的C代码
int ret = 0;
JNIEXPORT jint JNICALL Java_com_android_counter_Counter_readsd
(JNIEnv *env, jobject obj, jstring sdname, jint sectorstart, jcharArray buffer)
{
size_t sector_size = 0;
int col;
unsigned short *array;
unsigned char *buf;
// jboolean *buf;
int i;
// int res;
/*********** jstring to char * ***********/
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env,"java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"utf-8");
jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,sdname, mid, strencode);
jsize alen = (*env)->GetArrayLength(env,barr);
jbyte* ba = (*env)->GetByteArrayElements(env,barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env)->ReleaseByteArrayElements(env,barr, ba, 0);
int fd = open(rtn,O_RDONLY);
if (fd == -1)
{
// printf("Open \"sdname \" failed. %s\n",strerror(errno));
return errno;
}
// jchar * buf = (*env)->GetCharArrayElements(env,buffer,0);
ioctl(fd, BLKSSZGET, §or_size);
// buffer = (unsigned char*)malloc(sector_size);
buf = (unsigned char*)malloc(sector_size);
lseek(fd,sectorstart * sector_size ,SEEK_SET);
// ret = read(fd,buffer,(unsigned int)sector_size);
ret = read(fd,buf,(unsigned int)sector_size);
printf("%d",ret);
printf("\n");
// jcharArray iarr = (*env)->NewCharArray(env, sector_size);
(*env)->SetByteArrayRegion(env,buffer, 0, sector_size, buf);
if (ret < 0)
{
printf("Read sectors failed. %s\n",strerror(errno));
return errno;
}
close(fd);
return ret;
}
需要注意的是,这个函数将得到的扇区存储在了字符数组中,长度是512。可是C中char的长度为1,字节,而Java中char的长度为2字节。入口参数又是char test[512],哎,因此,在linux下必须对所得到的字符将其解析为字节。解析函数如下:
int i=0;
byte[] filebuffer;
byte[] b_temp=new byte[2];
filebuffer= new byte[512];
//将读取到的扇区转为字节.
for (i=0;i<256;i++)
{
b_temp=charToByte(c_test[i]);
filebuffer[2*i]=b_temp[0];
filebuffer[2*i+1]=b_temp[1];
}
c_test[512]是从扇区得到的内容。
基本上从以上知识就可以得到扇区的内容了。程序的完整代码基于版权的关系,无法完整提供。也算是个需要此操作的朋友提供一个思路吧。
原创文章,转载请完整转载。
有什么问题可以QQ探讨。QQ:2484908