最近做项目涉及到了怎么设置系统时间,起初觉得这个问题是很简单的,但是事实并非如此,在这个问题上卡壳了好几天。
试了好几种方法,总算有了一定的成果。
1:
第一反应是查看android setting的源码(packages\apps\Settings),因为系统-日期和时间里面有能够设置时间的选项。
在其DateTimeSettings里面发现了它是利用 Calendar和系统类SystemClock来进行设置时间,我依样画葫芦,却提示Unable to open alarm driver。
百度了下,对于这个问题众说缤纷,有说是缺少权限配置文件,有说是通过把应用改为系统应用,来达到使用这个api的目的。把应用改为系统应用肯定不能满足我的需求,于是我又去试了下前面的方法,我在配置文件里面增加了这个权限。
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
结果依然提示我 Unable to open alarm driver。
2:
因为我的应用允许Root,所以我第二反应是想到利用linux命令来进行设置系统时间。但是我试了好几种方法,
系统时间虽然可以设置,但是却出现了时间不准确,甚至系统崩溃重启的情况。
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 命令。
方法一:
public void setTime(long time) { if (ShellInterface.isSuAvailable()) { ShellInterface.runCommand("chmod 666 /dev/alarm"); SystemClock.setCurrentTimeMillis(time); ShellInterface.runCommand("chmod 664 /dev/alarm"); } }
/** * Interface to the Superuser shell on Android devices with some helper functions.<p/><p/> * Common usage for su shell:<p/> * <code>if(ShellInterface.isSuAvailable()) { ShellInterface.runCommand("reboot"); }</code> * <p/><p/> * To get process output as a String:<p/> * <code>if(ShellInterface.isSuAvailable()) { String date = ShellInterface.getProcessOutput("date"); }</code> * <p/><p/> * To run command with standard shell (no root permissions): * <code>ShellInterface.setShell("sh");</code><p/> * <code>ShellInterface.runCommand("date");</code> * <p/><p/> * Date: Mar 24, 2010 * Time: 4:14:07 PM * * @author serge */ 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) {} } } }
方法二:
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命令熟悉度不高,应当多加强多接触这方面的知识,弥补不足。