Android:Static storage paths aren’t available from AID_SYSTEM 错误分析及解决方法 2014-09-01 / 8,007 次 / 2 条 /

摘要:”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 卡时发生的。

Runtime Environment
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
备注:用系统的 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.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
从 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.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) 的话,就不会抛出异常。由此可以得到以下结论:

“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 上!),这样我们是不是就可以解决这个问题呢?

/**
 * @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 #
依然无法写入到 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 卡的话,我们尝试写入到应用内部存储目录:

/**
 * @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 #
在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
 * 
 * @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 ,依然是权限问题!

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 卡的读写权限呢?

/**
 * 
 * @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
根据测试结果,可以看出,在 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 Pad 上,并且这个 Android Pad 是提供解决方案的公司做 Framework 层的工程师来修改源代码的,我本人是做应用层的,对这个修改框架层的代码也不懂,但是在 CSDN 上发现一篇作者 ID 为 echojiangyq_fight 写的一篇文章,恰好是我这个问题,我将文章内容转载过来,以供参考(以下内容中没有看到作者提到是否处理 throwIfSystem()方法):

2015-12-03(四)新增思考:

个人认为,Android之所以增加这种访问权限限制,是基于隐私的考虑,是保证内置的Android应用不能访问公共存储空间,而对于非内置的应用,用户选择安装的同时,也自己承担了隐私安全的风险。

******************************************************

移植原来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,感谢他给予的参考,谢谢!

2014-12-25(Thu)
添加备注:
最近在做 Bluetooth 开发中遇到一个很奇怪的问题,就是关于调用系统的提示框提示用户开启 Bluetooth ,调用的是 Activity.startActivityForResult(Intent intent, int requestCode) 方法,在 Activity.onActivityResult(int requestCode, int resultCode, Intent data) 回调方法中监听用户是否点击了确认还是取消按钮,但是发现存在用户没有点击按钮,却出现状态回调的情况,还有就是点击了按钮,却没有得到回调,最终是通过查看 Bluetooth 设置的源码,才知道原来背后的逻辑是这样的。
从以上 Bluetooth 的问题我体会到,还是因为自己的思维方式、知识能力处于一个较低水平,如果说对于上面的这个问题,我能知道 Android 底层的知识,或者是尝试从底层的机制去寻找问题的答案,我也不会用到“猜测”的方式,来寻找问题的答案,而且很多东西,只懂得表面肤浅的东西,只知道是什么,不知道为什么,这样做是基于什么样的考虑。这个需要在以后的工作和学习中继续提升自己!
打赏
上一篇: « 下一篇: »
暂无相关文章

已有 2 条评论

  1. awen_PC

    写的非常详细,这就是我们搞技术人应有的态度啊。感谢分享。

    1. ifeegoo

      嘿嘿,多谢夸奖!希望这篇文章对你有所帮助,共同进步!

> 添加新评论