转自http://blog.sina.com.cn/s/blog_a28e3dd90101eqcz.html
异常LOG如下:
android.util.Log$TerribleFailure: Static storage paths aren't available from AID_SYSTEM
at android.util.Log.wtf(Log.java:276)
at android.os.Environment.throwIfSystem(Environment.java:663)
at android.os.Environment.getExternalStorageDirectory(Environment.java:336)
at android.app.Fragment.performResume(Fragment.java:1744)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1057)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1039)
at android.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1850)
at android.app.Activity.performResume(Activity.java:5210)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2936)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2978)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1420)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5405)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:853)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
at dalvik.system.NativeStart.main(Native Method)
对于该异常Log的分析,根据提示我们在相应的代码中查到了Exception的语句:
162 File sdcardDir = Environment.getExternalStorageDirectory();
继续跟进到getExternalStorageDirectory()这个方法看到framework中的源码:
public static File getExternalStorageDirectory() {
throwIfSystem();
return sCurrentUser.getExternalStorageDirectory();
}
继续跟进上面的throwIfSystem()方法可以看到相应framework中的源码:
private static void throwIfSystem() {
if (Process.myUid() == Process.SYSTEM_UID) {
Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable());
}
}
也就是说读取SD卡路径时系统会做一个判断,查看当前应用用的Shared id是android.system.uid,若是的话在访问sdcard的时候会有如下异常抛出:exception Static storage paths aren't available from AID_SYSTEM,但App还是可以正常运行的。从源码来看只要是和System用同一个uid的App都会有这个Exception。Google在设计Android系统设计这种机制,是为了防止系统应用APP在读取SD卡而导致存储数据泄露的安全问题,在拒绝系统权限App将数据写入sd卡,可以防止用户的sd卡丢失或损坏是,导致系统级应用出现问题,故设计了系统权限的app不能访问sd卡的机制。
实际我们在manifest文件中是有配置 android:sharedUserId="android.uid.system" ,也就是说当前应用是以systemUID在运行,那么如果理解无问题的话,那么在我们的代码中是每次运行都会抛出这个异常的log,但实际我们通过打log并没有看到抛出Static storage paths aren't available from AID_SYSTEM的log,所以继续跟进该问题,我们尝试在代码中打印Process.myUid() 和Process.SYSTEM_UID这两个值,实际打印结果如下:
第一次打印的结果如下:
第二次打印的结果如下:
实际结果发现当前的Process UID根本和 SYSTEM_UID不相同,我们跟进Process源码可以看到System UID默认值是1000,同时还发现Process UID实际上是一个动态分配的随机值。
我们通过adb shell ps 命令打印出的进程的信息如上图所示,同时我们在代码中通过log打印出的Process UID的信息如下图所示:
那么我们发现实际的进程的PID就是该进程的UID,两个值是相同的。但实际上应用的UID是随机的分配,那么意味着配置 android:sharedUserId="android.uid.system"的应用是完全有可能是分配到系统的UID。在此种情况下就会抛出该异常。
继续跟进该问题,我们发现对于Environment类中是有定义一个未公开的隐藏类UserEnvironment,在该类中是有重写getExternalStorageDirectory()方法。而该方法的代码与Environment类中的不同点是,没有调用throwIfSystem()方法。
public File getExternalStorageDirectory() {
return mExternalStorage;
}
这个方法的处理,是规避了上面Environment中的抛异常的问题。对于这个隐藏的UserEnvironment是出于防止开发大量使用的目的而需要隐藏,若不隐藏开发者大量使用该类,就会导致之前设置系统权限app访问sd卡的机制完全无效,所以对于特别情况可以使用该类。而创建这个类的目的是处理特别情况下的当某些系统级应用必须要有访问sd卡的权限时,可以使用UserEnvironment来处理。