错误分析
当前开发环境:
- 操作系统:Windows 8.1
- IDE:ADT Bundle v22.6.2
- 设备: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 下载:https://github.com/techexpertize/SignApk 用到的命令如下:
// 给未签名的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.flygoly.debug
用系统的 platform.x509.pem, platform.pk8 文件对应用进行签名方式如下:
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
运行程序的时候,发现 “Static storage paths aren’t available from AID_SYSTEM” 错误,并且发现写入 Micro SD 卡 Permission denied,错误日志如下:
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.flygoly.debug.utils.FileManager.saveToExternalStorageDirectory(FileManager.java:18)
A/Environment(1261): at com.flygoly.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/flygoly.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.flygoly.debug.utils.FileManager.saveToExternalStorageDirectory(FileManager.java:17)
W/System.err(1261): at com.flygoly.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
从 AID_SYSTEM、throwIfSystem、SYSTEM_UID 等字眼中可以看出当前应用和系统有关;同时从 /mnt/sdcard、Permission denied 等字眼中可以看出当前应用被禁止 Micro SD 卡写入,分析:
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.flygoly.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.flygoly.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.flygoly.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.flygoly.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.flygoly.debug
system 722 38 175676 20060 ffffffff 40037ebc S com.flygoly.debug
system 730 38 175676 20060 ffffffff 40037ebc S com.flygoly.debug
system 724 38 175676 20068 ffffffff 40037ebc S com.flygoly.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.flygoly.debug
u0_a46 705 38 175676 19968 ffffffff 40037ebc S com.flygoly.debug
u0_a46 697 38 175676 19968 ffffffff 40037ebc S com.flygoly.debug
u0_a46 699 38 175676 19960 ffffffff 40037ebc S com.flygoly.debug
u0_a46 773 38 175676 19968 ffffffff 40037ebc S com.flygoly.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) 的话,就不会抛出异常;由此可以得到以下结论:
“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 卡时发生的。
解决方法
接下来探讨解决方法:
由于此应用中的某些具有系统权限功能的原因,声明 android:sharedUserId=”android.uid.system”,并且通过系统的 platform.x509.pem 和 platform.pk8 文件签名的这两个前提是不会变的!
1. 由于涉及到向 Micro SD 卡写入数据,是调用 android.os.Environment 类中的 getExternalStorageDirectory() 方法得到外部存储路径的,我们可不可以采用 “hardcode” 方式直接写出已知外部存储路径(备注:此应用运行在定制的 Android Pad 上!),这样我们是不是就可以解决这个问题呢?
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/flygoly.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.flygoly.debug.utils.FileManager.saveToExternalStorageDirectory(FileManager.java:28)
W/System.err(5089): at com.flygoly.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 #
依然无法写入到 Micro SD 卡上,至于在哪个地方控制了这个权限问题,暂时不明(个人猜测是类似于 Linux 权限控制问题)。所以在 Android 4.2.2 中,用 “hardcode” 方法将外部存储目录由 Environment.getExternalStorageDirectory().getAbsolutePath() 改成 “mnt/sdcard” ,是可以避免 “Static storage paths aren’t available from AID_SYSTEM” 错误,但是依然会出现 Micro SD 卡写入 Permission denied !
2. 由于涉及到向 Micro SD 卡写入数据,如果说应用的数据不必非要写入 Micro SD 卡的话,我们尝试写入到应用内部存储目录:
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.flygoly.debug/files
cd /data/data/com.flygoly.debug/files
root@android:/data/data/com.flygoly.debug/files # ls
ls
flygoly.txt
root@android:/data/data/com.flygoly.debug/files # cat flygoly.txt
cat flygoly.txt
www.flygoly.com
root@android:/data/data/com.flygoly.debug/files #
在 Android 4.2.2 中,如果说应用的数据不必非要写入 Micro SD 卡的话,我们可以将数据写入到应用内部存储目录 /data/data/package name/files/ ,这样我们就可以解决报 “Static storage paths aren’t available from AID_SYSTEM” 错误,以及写入 Micro SD 卡时 Permission denied !
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
*/
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,依然是权限问题!
Android 4.2.2 API 中,调用 android.os.Environment 类中的隐藏类 UserEnvironment 中的 getExternalStorageDirectory() 方法,虽然可以避免 “Static storage paths aren’t available from AID_SYSTEM” 错误,但是依然会出现 Micro SD 卡写入 Permission denied !
4. 从上面的研究看来,即使不报 “Static storage paths aren’t available from AID_SYSTEM” 错误,也会出现读写权限的问题,那可不可以自己在应用中,自己更改 Micro SD 卡的读写权限呢?
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
flygoly.txt
www
root@generic:/mnt/sdcard # cat flygoly.txt
cat flygoly.txt
www.flygoly.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.flygoly.debug
根据测试结果,可以看出,在 Android 4.4.2 系统中,通过声明 android:sharedUserId=”android.uid.system”,并且通过系统的 platform.x509.pem 和 platform.pk8 文件签名的应用读写 Micro SD 卡是没有问题的,既然本应用是运行在定制的 Andorid Pad 上,因此我们可以考虑将 Android 4.2.2 系统更改成 Android 4.4.2 系统!
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 4.2.2 系统框架层的代码,并且更改应用对 Micro SD 卡读写权限来解决通过声明 android:sharedUserId=”android.uid.system”,并且通过系统的 platform.x509.pem 和 platform.pk8 文件签名的应用报 “Static storage paths aren’t available from AID_SYSTEM” 错误和无法写入 Micro SD 卡的问题!最终这个问题也是通过这样的方式解决的!
个人认为,Android之所以增加这种访问权限限制,是基于隐私的考虑,是保证内置的Android应用不能访问公共存储空间,而对于非内置的应用,用户选择安装的同时,也自己承担了隐私安全的风险。
备注:由于我的应用运行在定制的 Android Pad 上,并且这个 Android Pad 是提供解决方案的公司做 Framework 层的工程师来修改源代码的,我本人是做应用层的,对这个修改框架层的代码也不懂,但是在 CSDN 上发现一篇作者 ID 为 echojiangyq_fight 写的一篇文章,恰好是我这个问题,我将文章内容转载过来,以供参考(以下内容中没有看到作者提到是否处理 throwIfSystem()方法):
移植原来 v210(三星平台,Android 2.3 系统)的老程序到 MTK6575 Android 4.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
如果觉得文章对你有帮助,欢迎赞赏支持
