最近做项目涉及到了怎么设置系统时间,起初觉得这个问题是很简单的,但是事实并非如此,在这个问题上卡壳了好几天。
试了好几种方法,总算有了一定的成果。
1:
第一反应是查看android setting的源码(packages\apps\Settings),因为系统-日期和时间里面有能够设置时间的选项。
在其DateTimeSettings里面发现了它是利用 Calendar和系统类SystemClock来进行设置时间,我依样画葫芦,却提示Unable to open alarm driver。
百度了下,对于这个问题众说缤纷,有说是缺少权限配置文件,有说是通过把应用改为系统应用,来达到使用这个api的目的。把应用改为系统应用肯定不能满足我的需求,于是我又去试了下前面的方法,我在配置文件里面增加了这个权限。
Xml代码
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
结果依然提示我 Unable to open alarm driver。
2:
因为我的应用允许Root,所以我第二反应是想到利用linux命令来进行设置系统时间。但是我试了好几种方法,
系统时间虽然可以设置,但是却出现了时间不准确,甚至系统崩溃重启的情况。
Java代码
Runtime.getRuntime().exec("su");
RootTools.sendShell("date -s 20130409 \n",10);
RootTools.sendShell("date -s 1311420409637 \n",10);
3:
搜遍了所有的中文android论坛,对于这个问题的解决方法都是千篇一律,后来总算在stackoverflow上面找到了答案。
给出的解决方法有二种,一种是修改系统的/dev/alarm文件,一种是直接利用date -s 命令。
方法一:
Java代码
public void setTime(long time) {
if (ShellInterface.isSuAvailable()) {
ShellInterface.runCommand("chmod 666 /dev/alarm");
SystemClock.setCurrentTimeMillis(time);
}
}
Java代码
public class ShellInterface {
private static final String TAG = "ShellInterface";
private static String shell;
// uid=0(root) gid=0(root)
private static final Pattern UID_PATTERN = Pattern.compile("^uid=(\\d+).*?");
enum OUTPUT {
STDOUT,
STDERR,
BOTH
}
private static final String EXIT = "exit\n";
private static final String[] SU_COMMANDS = new String[]{
"su",
"/system/xbin/su",
"/system/bin/su"
};
private static final String[] TEST_COMMANDS = new String[]{
"id",
"/system/xbin/id",
"/system/bin/id"
};
public static synchronized boolean isSuAvailable() {
if (shell == null) {
checkSu();
}
return shell != null;
}
public static synchronized void setShell(String shell) {
ShellInterface.shell = shell;
}
private static boolean checkSu() {
for (String command : SU_COMMANDS) {
shell = command;
if (isRootUid()) return true;
}
shell = null;
return false;
}
private static boolean isRootUid() {
String out = null;
for (String command : TEST_COMMANDS) {
out = getProcessOutput(command);
if (out != null && out.length() > 0) break;
}
if (out == null || out.length() == 0) return false;
Matcher matcher = UID_PATTERN.matcher(out);
if (matcher.matches()) {
if ("0".equals(matcher.group(1))) {
return true;
}
}
return false;
}
public static String getProcessOutput(String command) {
try {
return _runCommand(command, OUTPUT.STDERR);
} catch (IOException ignored) {
return null;
}
}
public static boolean runCommand(String command) {
try {
_runCommand(command, OUTPUT.BOTH);
return true;
} catch (IOException ignored) {
return false;
}
}
private static String _runCommand(String command, OUTPUT o) throws IOException {
DataOutputStream os = null;
Process process = null;
try {
process = Runtime.getRuntime().exec(shell);
os = new DataOutputStream(process.getOutputStream());
InputStreamHandler sh = sinkProcessOutput(process, o);
os.writeBytes(command + '\n');
os.flush();
os.writeBytes(EXIT);
os.flush();
process.waitFor();
if (sh != null) {
String output = sh.getOutput();
Log.d(TAG, command + " output: " + output);
return output;
} else {
return null;
}
} catch (Exception e) {
final String msg = e.getMessage();
Log.e(TAG, "runCommand error: " + msg);
throw new IOException(msg);
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
process.destroy();
}
} catch (Exception ignored) {}
}
}
public static InputStreamHandler sinkProcessOutput(Process p, OUTPUT o) {
InputStreamHandler output = null;
switch (o) {
case STDOUT:
output = new InputStreamHandler(p.getErrorStream(), false);
new InputStreamHandler(p.getInputStream(), true);
break;
case STDERR:
output = new InputStreamHandler(p.getInputStream(), false);
new InputStreamHandler(p.getErrorStream(), true);
break;
case BOTH:
new InputStreamHandler(p.getInputStream(), true);
new InputStreamHandler(p.getErrorStream(), true);
break;
}
return output;
}
private static class InputStreamHandler extends Thread {
private final InputStream stream;
private final boolean sink;
StringBuffer output;
public String getOutput() {
return output.toString();
}
InputStreamHandler(InputStream stream, boolean sink) {
this.sink = sink;
this.stream = stream;
start();
}
@Override
public void run() {
try {
if (sink) {
while (stream.read() != -1) {}
} else {
output = new StringBuffer();
BufferedReader b = new BufferedReader(new InputStreamReader(stream));
String s;
while ((s = b.readLine()) != null) {
output.append(s);
}
}
} catch (IOException ignored) {}
}
}
}
方法二:
Java代码
public void setDate()
{
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("date -s 20120419.024012; \n");
} catch (Exception e) {
Log.d(TAG,"error=="+e.toString());
e.printStackTrace();
}
}
总结:出现了这种问题,归根究底在于我自己的知识积累不够,对于linux命令熟悉度不高,应当多加强多接触这方面的知识,弥补不足。
提示,测试机器必须ROOT,否则无法修改。