OS: Windows 8.1
IDE: ADT Bundle v22.6.2
Device: Android Official Simulator
为了方便读者读到我这篇文章的时候,能够对文章内容进行验证,我将测试环境换成了 Android 官方的模拟器,因为本应用采用了系统对应的 platform.x509.pem 和 platform.pk8 文件签名,而模拟器的对应的这两个文件,读者是方便拿到的,而我自己开发应用是运行在定制的 Android Pad 上面,即使我公开了 platform.x509.pem 和 platform.pk8 这两个文件,读者也是无法测试的,因为这两个文件根据 ROM 的不同而不同的。
适用于 Android 官方模拟器的 platform.x509.pem 和 platform.pk8 这两个文件可以在GitHub上下载:https://github.com/android/platform_build/tree/master/target/product/security
签名工具 signapk.jar 下载:http://url.cn/Pmgjeq 用到的命令如下;
// 给未签名的apk文件用系统对应的 platform.x509.pem 和 platform.pk8 两个文件签名 java -jar signapk.jar platform.x509.pem platform.pk8 debug.apk debug_signed.apk // ADB 安装和卸载的命令 adb install debug_signed.apk adb uninstall com.ifeegoo.debug
1. 用 eclipse 导出未签名的应用 debug.apk 。
2. 用签名工具 signapk.jar 和系统对应的 platform.x509.pem, platform.pk8 文件通过以下命令得到具备系统签名的debug_signed.apk 。
java -jar signapk.jar platform.x509.pem platform.pk8 debug.apk debug_signed.apk
A/Environment(1261): Static storage paths aren't available from AID_SYSTEM A/Environment(1261): java.lang.Throwable A/Environment(1261): at android.os.Environment.throwIfSystem(Environment.java:637) A/Environment(1261): at android.os.Environment.getExternalStorageDirectory(Environment.java:316) A/Environment(1261): at com.ifeegoo.debug.utils.FileManager.saveToExternalStorageDirectory(FileManager.java:18) A/Environment(1261): at com.ifeegoo.debug.activities.MainActivity$1.run(MainActivity.java:23) A/Environment(1261): at java.lang.Thread.run(Thread.java:856) W/System.err(1261): java.io.FileNotFoundException: /mnt/sdcard/ifeegoo.txt: open failed: EACCES (Permission denied) W/System.err(1261): at libcore.io.IoBridge.open(IoBridge.java:416) W/System.err(1261): at java.io.FileOutputStream.<init>(FileOutputStream.java:88) W/System.err(1261): at java.io.FileOutputStream.<init>(FileOutputStream.java:73) W/System.err(1261): at com.ifeegoo.debug.utils.FileManager.saveToExternalStorageDirectory(FileManager.java:17) W/System.err(1261): at com.ifeegoo.debug.activities.MainActivity$1.run(MainActivity.java:23) W/System.err(1261): at java.lang.Thread.run(Thread.java:856) W/System.err(1261): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied) W/System.err(1261): at libcore.io.Posix.open(Native Method) I/Choreographer(1261): Skipped 63 frames! The application may be doing too much work on its main thread. W/System.err(1261): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110) W/System.err(1261): at libcore.io.IoBridge.open(IoBridge.java:400) W/System.err(1261): ... 5 more
1. 由于当前应用涉及到一些和系统权限相关的功能,在配置文件中有 android:sharedUserId=”android.uid.system” 的声明,并且通过系统对应的 platform.x509.pem, platform.pk8 文件来对应用签名。
2. 应用会将一些数据保存在 Micro SD 卡上。
应用通过系统对应的 platform.x509.pem 和 platform.pk8 文件签名,AndroidManifest.xml 中有声明 android:sharedUserId=”android.uid.system” 和写入 Micro SD卡权限:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ifeegoo.debug"
android:sharedUserId="android.uid.system"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/icon_launcher" >
<activity
android:name="com.ifeegoo.debug.activities.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
通过错误日志第3行的提示,查找源代码,发现在 android.os.Environment 这个类中,有以下方法产生以上错误:
private static void throwIfSystem()
{
if (Process.myUid() == Process.SYSTEM_UID)
{
Log.wtf(TAG,
"Static storage paths aren't available from AID_SYSTEM",
new Throwable());
}
}
当 Process.myUid() 的值与 Process.SYSTEM_UID 的值相等时,会抛出异常!查看 android.os.Process 这个类,有如下说明,由于个人英语水平和Linux知识有限,不能理解。但是可以通过另外的方法来验证以上条件是否成立。
/**
* Defines the UID/GID under which system code runs.
*/
public static final int SYSTEM_UID = 1000;
/**
* Returns the identifier of this process's uid. This is the kernel uid
* that the process is running under, which is the identity of its
* app-specific sandbox. It is different from {@link #myUserHandle} in that
* a uid identifies a specific app sandbox in a specific user.
*/
public static final native int myUid();
通过应用内打印日志的方式,发现如下结果:
D/Process(1806): Process.myUid() = 1000
凭借着自己的对进程ID的一点认识,觉得这个值会不会变呢?会不会这次恰巧是1000呢,通过5次的验证,发现如下结果:
备注:每一次都是卸载重新安装重启之后打开应用测试的结果!
08-28 09:31:26.149: D/Process(995): Process.myUid() = 1000 08-28 09:35:18.577: D/Process(718): Process.myUid() = 1000 08-28 09:38:43.600: D/Process(722): Process.myUid() = 1000 08-28 09:41:40.382: D/Process(730): Process.myUid() = 1000 08-28 09:44:17.761: D/Process(724): Process.myUid() = 1000
通过 adb shell 的 ps 命令,查看到本应用 com.ifeegoo.debug 的 USER 标识为 system :
C:\>adb shell root@android:/ # ps ps USER PID PPID VSIZE RSS WCHAN PC NAME root 1 0 296 208 c0098770 0000e840 S /init root 2 0 0 0 c005048c 00000000 S kthreadd root 3 2 0 0 c0042268 00000000 S ksoftirqd/0 root 4 2 0 0 c004ce30 00000000 S events/0 root 5 2 0 0 c004ce30 00000000 S khelper root 6 2 0 0 c004ce30 00000000 S suspend root 7 2 0 0 c004ce30 00000000 S kblockd/0 root 8 2 0 0 c004ce30 00000000 S cqueue root 9 2 0 0 c016f7c4 00000000 S kseriod root 10 2 0 0 c004ce30 00000000 S kmmcd root 11 2 0 0 c006f36c 00000000 S pdflush root 12 2 0 0 c006f36c 00000000 S pdflush root 13 2 0 0 c007340c 00000000 S kswapd0 root 14 2 0 0 c004ce30 00000000 S aio/0 root 25 2 0 0 c016d0f8 00000000 S mtdblockd root 26 2 0 0 c004ce30 00000000 S kstriped root 27 2 0 0 c004ce30 00000000 S hid_compat root 28 2 0 0 c004ce30 00000000 S rpciod/0 root 29 2 0 0 c0189ddc 00000000 S mmcqd root 30 1 292 172 c0098770 0000e840 S /sbin/ueventd system 31 1 836 348 c0195c08 40036fc0 S /system/bin/servicemanager root 32 1 4008 860 ffffffff 4003e76c S /system/bin/vold root 34 1 8632 1252 ffffffff 4006a76c S /system/bin/netd root 35 1 880 388 c01a10a0 40037a70 S /system/bin/debuggerd radio 36 1 5468 836 ffffffff 4003776c S /system/bin/rild system 37 1 13388 3196 ffffffff 4006bfc0 S /system/bin/surfaceflinger root 38 1 165936 33672 ffffffff 400370e4 S zygote drm 39 1 6564 2320 ffffffff 400befc0 S /system/bin/drmserver media 40 1 23040 6404 ffffffff 4008cfc0 S /system/bin/mediaserver install 41 1 848 472 c021db90 40036d50 S /system/bin/installd keystore 42 1 1796 892 c01a10a0 40037a70 S /system/bin/keystore root 43 1 828 372 c00b4eb0 40037ebc S /system/bin/qemud shell 46 1 764 460 c0148178 40031d50 S /system/bin/sh root 47 1 5524 300 ffffffff 00015ef0 S /sbin/adbd system 278 38 248768 43040 ffffffff 40036fc0 S system_server u0_a23 399 38 182520 33800 ffffffff 40037ebc S com.android.systemui u0_a24 426 38 177720 20876 ffffffff 40037ebc S com.android.inputmethod.latin radio 444 38 197980 26020 ffffffff 40037ebc S com.android.phone system 458 38 183816 19280 ffffffff 40037ebc S com.android.settings u0_a4 503 38 201724 33892 ffffffff 40037ebc S android.process.acore u0_a5 519 38 194748 35200 ffffffff 40037ebc S com.android.launcher u0_a32 528 38 176204 17928 ffffffff 40037ebc S com.android.music u0_a10 558 38 180700 21524 ffffffff 40037ebc S android.process.media u0_a1 573 38 177700 17544 ffffffff 40037ebc S com.android.quicksearchbox u0_a4 620 38 183928 21000 ffffffff 40037ebc S com.android.contacts u0_a16 642 38 174268 16404 ffffffff 40037ebc S com.android.location.fused u0_a3 657 38 180948 20592 ffffffff 40037ebc S com.android.mms u0_a6 681 38 178692 19916 ffffffff 40037ebc S com.android.deskclock u0_a28 703 38 183548 17936 ffffffff 40037ebc S com.android.exchange u0_a33 725 38 180920 19316 ffffffff 40037ebc S com.android.providers.calendar u0_a26 741 38 186104 20064 ffffffff 40037ebc S com.android.calendar u0_a9 933 38 176340 16664 ffffffff 40037ebc S com.android.defcontainer u0_a14 951 38 174256 16012 ffffffff 40037ebc S com.svox.pico root 984 47 752 432 c002a7a0 4003294c S /system/bin/sh root 986 984 720 412 c0098770 400370e4 S logcat system 995 38 175676 20056 ffffffff 40037ebc S com.ifeegoo.debug root 1014 47 764 480 c002a7a0 4003294c S /system/bin/sh root 1019 1014 1092 436 00000000 40036d50 R ps
其它4次的结果:
C:\>adb shell root@android:/ # ps ps USER PID PPID VSIZE RSS WCHAN PC NAME *** system 718 38 175676 20060 ffffffff 40037ebc S com.ifeegoo.debug system 722 38 175676 20060 ffffffff 40037ebc S com.ifeegoo.debug system 730 38 175676 20060 ffffffff 40037ebc S com.ifeegoo.debug system 724 38 175676 20068 ffffffff 40037ebc S com.ifeegoo.debug
去掉应用 AndroidManifest.xml 文件中的 android:sharedUserId=”android.uid.system” 的声明,还是用系统对应的 platform.x509.pem, platform.pk8 文件对应用进行签名,得到的测试结果:
08-28 10:19:01.193: D/Process(1448): Process.myUid() = 10046 08-28 10:22:45.724: D/Process(705): Process.myUid() = 10046 08-28 10:24:54.461: D/Process(697): Process.myUid() = 10046 08-28 10:27:49.170: D/Process(699): Process.myUid() = 10046 08-28 10:29:59.600: D/Process(708): Process.myUid() = 10046
C:\>adb shell root@android:/ # ps ps USER PID PPID VSIZE RSS WCHAN PC NAME *** u0_a46 1448 38 175676 19956 ffffffff 40037ebc S com.ifeegoo.debug u0_a46 705 38 175676 19968 ffffffff 40037ebc S com.ifeegoo.debug u0_a46 697 38 175676 19968 ffffffff 40037ebc S com.ifeegoo.debug u0_a46 699 38 175676 19960 ffffffff 40037ebc S com.ifeegoo.debug u0_a46 773 38 175676 19968 ffffffff 40037ebc S com.ifeegoo.debug
从以上结果可以看到,去掉应用 AndroidManifest.xml 文件中的 android:sharedUserId=”android.uid.system” 的声明,然后 Process.myUid() 的值也不等于 1000,同时 USER 标识也变成了 u0_a46,再者,android.os.Environment 这个类中的 throwIfSystem()
方法是在以下方法中调用:
public static File getExternalStorageDirectory()
{
throwIfSystem();
return sCurrentUser.getExternalStorageDirectory();
}
同时,通过查看源代码和逐一测试得到以下结果:
—Android 4.2.2 以下版本是不会报 “Static storage paths aren’t available from AID_SYSTEM” 错误,但是会报文件写入 Permission denied 。
—Android 4.3 不会报 “Static storage paths aren’t available from AID_SYSTEM” 错误,但是会报文件写入 Permission denied 。
—Android 4.4.2 不会报 “Static storage paths aren’t available from AID_SYSTEM” 错误,并且能够写入成功!!!!!!
/**
* Android 4.2.2 以下
*
*/
public class Environment
{
public static File getExternalStorageDirectory()
{
return EXTERNAL_STORAGE_DIRECTORY;
}
}
/**
* Android 4.2.2
*
*/
public class Environment
{
public static File getExternalStorageDirectory()
{
throwIfSystem();
return sCurrentUser.getExternalStorageDirectory();
}
private static void throwIfSystem()
{
if (Process.myUid() == Process.SYSTEM_UID)
{
Log.wtf(TAG,
"Static storage paths aren't available from AID_SYSTEM",
new Throwable());
}
}
}
/**
* Android 4.3 / Android 4.4.2
*/
public class Environment
{
private static boolean sUserRequired;
public static File getExternalStorageDirectory()
{
throwIfUserRequired();
return sCurrentUser.getExternalStorageDirectory();
}
/** {@hide} */
public static void setUserRequired(boolean userRequired)
{
sUserRequired = userRequired;
}
private static void throwIfUserRequired()
{
if (sUserRequired)
{
Log.wtf(TAG,
"Path requests must specify a user by using UserEnvironment",
new Throwable());
}
}
}
从以上 Android 4.3 / Android 4.4.2 代码可以看到,如果不调用隐藏方法 setUserRequired(boolean userRequired) 的话,就不会抛出异常。由此可以得到以下结论:
探讨解决方法:
1. 由于涉及到向 Micro SD 卡写入数据,是调用 android.os.Environment 类中的 getExternalStorageDirectory() 方法得到外部存储路径的,我们可不可以采用 “hardcode” 方式直接写出已知外部存储路径(备注:此应用运行在定制的 Android Pad 上!),这样我们是不是就可以解决这个问题呢?
/**
* @author ifeegoo www.ifeegoo.com
*/
public static void saveToExternalStorageDirectory(String filename,
String content)
{
if ((filename == null) || (content == null))
{
return;
}
FileOutputStream fileOutputStream = null;
try
{
// 将 Environment.getExternalStorageDirectory().getAbsolutePath() 替换成 "mnt/sdcard"
fileOutputStream = new FileOutputStream(new File("mnt/sdcard",
filename));
fileOutputStream.write(content.getBytes());
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
} finally
{
try
{
if (fileOutputStream != null)
{
fileOutputStream.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
W/System.err(5089): java.io.FileNotFoundException: /mnt/sdcard/ifeegoo.txt: open failed: EACCES (Permission denied) W/System.err(5089): at libcore.io.IoBridge.open(IoBridge.java:416) W/System.err(5089): at java.io.FileOutputStream.<init>(FileOutputStream.java:88) W/System.err(5089): at java.io.FileOutputStream.<init>(FileOutputStream.java:73) W/System.err(5089): at com.ifeegoo.debug.utils.FileManager.saveToExternalStorageDirectory(FileManager.java:28) W/System.err(5089): at com.ifeegoo.debug.activities.MainActivity$1.run(MainActivity.java:23) W/System.err(5089): at java.lang.Thread.run(Thread.java:856) W/System.err(5089): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied) W/System.err(5089): at libcore.io.Posix.open(Native Method)
在Android 4.2.2 中测试,从以上日志可以看到,虽然没有报 “Static storage paths aren’t available from AID_SYSTEM” 错误,但是依然会有无法写入文件,Permission denied 。检查是否写入文件:
C:\>adb shell root@android:/ # cd /mnt/sdcard cd /mnt/sdcard root@android:/mnt/sdcard # ls ls Alarms Android DCIM Download LOST.DIR Movies Music Notifications Pictures Podcasts Ringtones www root@android:/mnt/sdcard #
2. 由于涉及到向 Micro SD 卡写入数据,如果说应用的数据不必非要写入 Micro SD 卡的话,我们尝试写入到应用内部存储目录:
/**
* @author ifeegoo www.ifeegoo.com
*/
public static void saveToInternalFilesDirectory(Context context,
String filename, String content)
{
if ((context == null) || (filename == null) || (content == null))
{
return;
}
FileOutputStream fileOutputStream = null;
try
{
fileOutputStream = new FileOutputStream(new File(context
.getFilesDir().getAbsolutePath(), filename));
fileOutputStream.write(content.getBytes());
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
} finally
{
try
{
if (fileOutputStream != null)
{
fileOutputStream.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
检查是否写入到内部存储目录:
C:\>adb shell root@android:/ # cd /data/data/com.ifeegoo.debug/files cd /data/data/com.ifeegoo.debug/files root@android:/data/data/com.ifeegoo.debug/files # ls ls ifeegoo.txt root@android:/data/data/com.ifeegoo.debug/files # cat ifeegoo.txt cat ifeegoo.txt www.ifeegoo.com root@android:/data/data/com.ifeegoo.debug/files #
3. Android 4.2.2 API 中,从 android.os.Environment 这个类中,发现有一个隐藏的静态内部类,里面也有一个方法为 getExternalStorageDirectory() ,同时这个方法并没有调用 throwIfSystem() 方法,如果说能够用反射来调用这个里面的方法,是不是就可以解决这个问题呢?
public class Environment
{
/** {@hide} */
public static class UserEnvironment
{
public File getExternalStorageDirectory()
{
return mExternalStorage;
}
}
}
/**
* UserEnvironment 类的构造方法中需要传入 userId,不明白这个 userId,暂且传入一个int数值0
*
* @author ifeegoo www.ifeegoo.com
*
*/
public class ReflectManager
{
public static String getExternalStoragePath()
{
try
{
Class<?> klass = Class
.forName("android.os.Environment$UserEnvironment");
Method method = klass
.getDeclaredMethod("getExternalStorageDirectory");
Object object = method.invoke(klass.getConstructor(int.class)
.newInstance(new Object[] { 0 }));
if (object != null)
{
return object.toString();
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (NoSuchMethodException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
} catch (IllegalArgumentException e)
{
e.printStackTrace();
} catch (InvocationTargetException e)
{
e.printStackTrace();
} catch (InstantiationException e)
{
e.printStackTrace();
}
return null;
}
}
这样是可以避免抛出异常,但是以上方法其实和第一种方法一样,虽然避免了采用那种 “hardcode” 方式来获取外部存储路径,但是依然写入 Micro SD 卡,出现 Permission denied ,依然是权限问题!
4. 从上面的研究看来,即使不报 “Static storage paths aren’t available from AID_SYSTEM” 错误,也会出现读写权限的问题,那可不可以自己在应用中,自己更改 Micro SD 卡的读写权限呢?
/**
*
* @author ifeegoo www.ifeegoo.com
*
*/
public class AdbShellManager
{
public static String chmod777(String path)
{
String[] args = { "chmod", "777", path, "\n" };
ProcessBuilder processBuilder = new ProcessBuilder(args);
String result = null;
Process process = null;
InputStream standardErrorInputStream = null;
InputStream standardOutInputStream = null;
try
{
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int read = -1;
if (processBuilder != null)
{
process = processBuilder.start();
}
standardErrorInputStream = process.getErrorStream();
if (standardErrorInputStream != null)
{
while ((read = standardErrorInputStream.read()) != -1)
{
byteArrayOutputStream.write(read);
}
}
byteArrayOutputStream.write('\n');
standardOutInputStream = process.getInputStream();
if (standardOutInputStream != null)
{
while ((read = standardOutInputStream.read()) != -1)
{
byteArrayOutputStream.write(read);
}
}
result = new String(byteArrayOutputStream.toByteArray());
} catch (IOException e)
{
e.printStackTrace();
} catch (Exception e)
{
e.printStackTrace();
} finally
{
try
{
if (standardErrorInputStream != null)
{
standardErrorInputStream.close();
}
if (standardOutInputStream != null)
{
standardOutInputStream.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
if (process != null)
{
process.destroy();
}
}
return result;
}
}
在以上 AdbShellManager 类中的 chmod777(String path) 方法传入 “mnt/sdcard” ,在 Android 4.2.2 系统中的测试结果如下:
08-31 23:04:25.404: D/chmod777(971): Unable to chmod 08-31 23:04:25.404: D/chmod777(971): : No such file or directory
以上结果提示 “Unable to chmod” , “No such file or directory”。我们查看目录是否存在:
C:\>adb shell root@android:/mnt/sdcard # cd /mnt/sdcard cd /mnt/sdcard root@android:/mnt/sdcard # ls ls Alarms Android DCIM Download LOST.DIR Movies Music Notifications Pictures Podcasts Ringtones www
可以看到 “mnt/sdcard” 目录是存在的,但是不知道为什么提示“无此文件或目录”,难道是因为更改权限没有成功或者访问权限的问题?尝试先请求 root 权限,将 AdbShellManager 类中的 chmod777(String path)
方法中的 String[] args = { “chmod”, “777”, path, “\n” };
更改成 String[] args = { “su”, “\n”, “chmod”, “777”, path, “\n” }; 测试结果如下:
08-31 23:22:13.765: D/chmod777(1337): uid 1000 not allowed to su
以上结果提示拒绝获得 root 权限。
对比模拟器和定制的 Android Pad 两个版本的 Android 4.2.2 中 Micro SD 卡写入权限:
// 在当前路径下用 ls -l 可以查看当前路径的读写权限 // Android Simulator d---rwxr-x system sdcard_rw 1970-01-01 00:00 sdcard // Android Pad drwxrwxr-x system sdcard_rw 2014-09-01 19:07 sdcard
5. 既然本应用是运行在定制的 Android Pad 上,通过源代码可以看到,只有 Android 4.2.2 才会出现报 “Static storage paths aren’t available from AID_SYSTEM” 错误,那么我们可以将当前运行在 Android Pad 上的 Android 4.2.2 系统换成 Android 4.4.2,这样是否就可以解决这个问题了呢?
C:\>adb shell root@android:/mnt/sdcard # cd /mnt/sdcard cd /mnt/sdcard root@generic:/mnt/sdcard # ls ls Alarms Android DCIM Download LOST.DIR Movies Music Notifications Pictures Podcasts Ringtones ifeegoo.txt www root@generic:/mnt/sdcard # cat ifeegoo.txt cat ifeegoo.txt www.ifeegoo.com root@generic:/mnt/sdcard #
再确认下应用的 USER 标识:
C:\>adb shell root@generic:/ # ps ps USER PID PPID VSIZE RSS WCHAN PC NAME *** system 1270 54 214952 20884 ffffffff b6efe5cc S com.ifeegoo.debug
6. 既然本应用是运行在定制的 Android Pad 上,因为在 Android 4.2.2 系统中的 android.os.Environment 类中的 getExternalStorageDirectory() 方法调用了 throwIfSystem() 方法,导致了报 “Static storage paths aren’t available from AID_SYSTEM” 错误,同时由于系统限制了通过声明 android:sharedUserId=”android.uid.system”,并且通过系统的 platform.x509.pem 和 platform.pk8 文件签名的应用读写 Micro SD 卡权限,那么我们可否通过更改框架层的代码,并且更改应用对 Micro SD 卡读写权限来解决以上问题呢?
答案是肯定的!
备注:由于我的应用运行在定制的 Android Pad 上,并且这个 Android Pad 是提供解决方案的公司做 Framework 层的工程师来修改源代码的,我本人是做应用层的,对这个修改框架层的代码也不懂,但是在 CSDN 上发现一篇作者 ID 为 echojiangyq_fight 写的一篇文章,恰好是我这个问题,我将文章内容转载过来,以供参考(以下内容中没有看到作者提到是否处理 throwIfSystem()方法):
2015-12-03(四)新增思考:
******************************************************
移植原来v210(三星平台,android2.3系统)的老程序到mtk6575 android4.2上,遇到的一个问题,因为要读写settings的共享数据库,必须要获得system uid,但是这时向sdcard写log时就会遇到权限问题,陷入两者不能兼得的尴尬境地。因为有源码,选择了修改void从而对system uid开放scard写权限的方式。原来的sdcard权限:
root@android:/system/bin # ls -l /storage/sdcard0 ls -l /storage/sdcard0 ----rwxr-x system sdcard_rw 7390845 2012-12-15 10:43 22.mp4 d---rwxr-x system sdcard_rw 2013-05-29 00:00 Alarms d---rwxr-x system sdcard_rw 2013-05-29 00:00 Android d---rwxr-x system sdcard_rw 2013-05-29 00:00 DCIM d---rwxr-x system sdcard_rw 2013-05-29 00:00 Download d---rwxr-x system sdcard_rw 2013-05-29 00:10 LOST.DIR d---rwxr-x system sdcard_rw 2014-05-30 14:57 MTK d---rwxr-x system sdcard_rw 2013-05-29 00:00 Movies d---rwxr-x system sdcard_rw 2014-05-30 14:08 Music d---rwxr-x system sdcard_rw 2013-05-29 00:00 Notifications d---rwxr-x system sdcard_rw 2013-05-29 00:00 Pictures d---rwxr-x system sdcard_rw 2013-05-29 00:00 Podcasts d---rwxr-x system sdcard_rw 2014-05-29 19:29 Recording d---rwxr-x system sdcard_rw 2013-05-29 00:00 Ringtones d---rwxr-x system sdcard_rw 2014-05-30 17:51 TestDetailLogs d---rwxr-x system sdcard_rw 2013-05-29 01:02 mtklog d---rwxr-x system sdcard_rw 2014-05-30 17:35 test
修改源码 /system/vold/Volume.cpp
#ifdef MTK_EMMC_DISCARD
// 0702 --> 0002
if (Fat::doMount(devicePath, "mnt/secure/staging", false, false, false,
AID_SYSTEM, gid, 0002, true, IsEmmcStorage()))
{
SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
continue;
}
#else //MTK_EMMC_DISCARD
// 0702 --> 0002
if (Fat::doMount(devicePath, "mnt/secure/staging", false, false, false,
AID_SYSTEM, gid, 0002, true))
{
SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
continue;
}
#endif //MTK_EMMC_DISCARD
修改后编译产生新的void可执行文件,adb push到/system/bin,加上可执行权限,关机重新开机,权限开放!再次查看 SD 卡读写权限:
root@android:/system/bin # ls -l /storage/sdcard0 ls -l /storage/sdcard0 -rwxrwxr-x system sdcard_rw 7390845 2012-12-15 10:43 22.mp4 drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Alarms drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Android drwxrwxr-x system sdcard_rw 2013-05-29 00:00 DCIM drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Download drwxrwxr-x system sdcard_rw 2013-05-29 00:10 LOST.DIR drwxrwxr-x system sdcard_rw 2014-05-30 14:57 MTK drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Movies drwxrwxr-x system sdcard_rw 2014-05-30 14:08 Music drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Notifications drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Pictures drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Podcasts drwxrwxr-x system sdcard_rw 2014-05-29 19:29 Recording drwxrwxr-x system sdcard_rw 2013-05-29 00:00 Ringtones drwxrwxr-x system sdcard_rw 2014-05-30 17:51 TestDetailLogs drwxrwxr-x system sdcard_rw 2013-05-29 01:02 mtklog drwxrwxr-x system sdcard_rw 2014-05-30 17:35 test
******************************************************
说明:以上两行”*”号中间的内容来自 CSDN 作者 ID 为 echojiangyq_fight的博客文章:
http://blog.csdn.net/echojiangyq_fight/article/details/28232953,感谢他给予的参考,谢谢!
添加备注:
最近在做 Bluetooth 开发中遇到一个很奇怪的问题,就是关于调用系统的提示框提示用户开启 Bluetooth ,调用的是 Activity.startActivityForResult(Intent intent, int requestCode) 方法,在 Activity.onActivityResult(int requestCode, int resultCode, Intent data) 回调方法中监听用户是否点击了确认还是取消按钮,但是发现存在用户没有点击按钮,却出现状态回调的情况,还有就是点击了按钮,却没有得到回调,最终是通过查看 Bluetooth 设置的源码,才知道原来背后的逻辑是这样的。

微信扫一扫,打赏作者吧~