摘要:”Static storage paths aren’t available from AID_SYSTEM” 错误是 Android 4.2.2 系统中通过声明 android:sharedUserId=”android.uid.system”,并且通过系统对应的 platform.x509.pem 和 platform.pk8 文件签名的应用读写 Micro SD 卡时发生的。
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 设置的源码,才知道原来背后的逻辑是这样的。