在 Android 作業系統裡, 我們可以利用作業系統裡的FileObserver 進行 Process 之間的溝通.
Check If File Exists
"Content.txt" 是我們 Process 之間溝通的檔案. 我們必須確認這個檔案是存在的, 然後才可以使用 FileObserver . 當 new File().isFile() 返回 TRUE 時, 表示該檔案存在; 反之; 返回 FALSE 時, 表示該檔案不存在.
txtFile = new File("/mnt/asec/Content.txt"); if (!txtFile.isFile()) { Log.i("atgames", "file not exist"); } else { Log.i("atgames", "file exist"); }
RandomAccessFile
try { randomTxtFile = new RandomAccessFile(txtFile, "r"); } catch (FileNotFoundException e) { e.printStackTrace(); }
FileObserver
我們使用 new FileObserver().onEvent(int event, String path) 來處理當 "Content.txt" 檔案內容改變時的事件 (也就是 event == FileObserver.MODIFY) . 當檔案內容改變時我們要讀取檔案的內容; 需注意的是每一次 readLine() 之前都 seek(0) . 我喜歡將發生事件時的函數, 將它的開頭冠以 onXxx ; 在這裡我將它命名為 onFileObserver() ; 在這個函數裡面, 我們將處理來自於另一個 Process 改變 "Content.txt" 檔案的內容.
設定 FileObserver 處理函數 onEvent() 以及 onFileObserver() 後, 我們還必須做一件事情: new FileObserver().startWatching() . startWatching() 以後作業系統才會 callBack 至 fileObserver.onEvent() .
private File txtFile; private RandomAccessFile randomTxtFile; private void startFileObserver() { static int once = 0; txtFile = new File("/mnt/asec/Content.txt"); if (!txtFile.isFile()) { Log.i("atgames", "file not exist"); return; } if (0 == once) { Process process = null; DataOutputStream dataOutputStream = null; process = Runtime.getRuntime().exec("su"); dataOutputStream = new DataOutputStream(process.getOutputStream()); dataOutputStream.writeBytes("chmod 666 /mnt/asec/Content.txt\n"); dataOutputStream.writeBytes("exit\n"); dataOutputStream.flush(); process.waitFor(); once = 1; } try { randomTxtFile = new RandomAccessFile(txtFile, "r"); } catch (FileNotFoundException e) { e.printStackTrace(); } fileObserver = new FileObserver("/mnt/asec/Content.txt") { @Override public void onEvent(int event, String path) { if (event == FileObserver.MODIFY) { try { randomTxtFile.seek(0); onFileObserver(randomTxtFile.readLine()); } catch (IOException e) { e.printStackTrace(); } } } }; fileObserver.startWatching(); } private void onFileObserver(String input){ if(input == null) return; ... }
使用 "su"
我們使用 su 來改變檔案讀取權限, 代碼如下:
Process process = null; DataOutputStream dataOutputStream = null; process = Runtime.getRuntime().exec("su"); dataOutputStream = new DataOutputStream(process.getOutputStream()); dataOutputStream.writeBytes("chmod 666 /mnt/asec/Content.txt\n"); dataOutputStream.writeBytes("exit\n"); dataOutputStream.flush(); process.waitFor();
Android 只有 root (AID_ROOT) 以及 shell (AID_SHELL) 可以使用 su 命令.
http://www.netmite.com/android/mydroid/system/core/include/private/android_filesystem_config.h
... static struct android_id_info android_ids[] = { { "root", AID_ROOT, }, { "system", AID_SYSTEM, }, { "radio", AID_RADIO, }, { "bluetooth", AID_BLUETOOTH, }, { "graphics", AID_GRAPHICS, }, { "input", AID_INPUT, }, { "audio", AID_AUDIO, }, { "camera", AID_CAMERA, }, { "log", AID_LOG, }, { "compass", AID_COMPASS, }, { "mount", AID_MOUNT, }, { "wifi", AID_WIFI, }, { "dhcp", AID_DHCP, }, { "adb", AID_ADB, }, { "install", AID_INSTALL, }, { "media", AID_MEDIA, }, { "shell", AID_SHELL, }, { "cache", AID_CACHE, }, { "diag", AID_DIAG, }, { "net_bt_admin", AID_NET_BT_ADMIN, }, { "net_bt", AID_NET_BT, }, { "inet", AID_INET, }, { "net_raw", AID_NET_RAW, }, { "misc", AID_MISC, }, { "nobody", AID_NOBODY, }, }; ...
為此你必須修改 su.c ; 它的代碼如下:
https://android.googlesource.com/platform/system/extras/+/android-4.2.2_r1.2/su/su.c
如果你要修改 su.c , 請將 su.c 之 51,69行 mark 起來.
/* ** ** Copyright 2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "su" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <dirent.h> #include <errno.h> #include <unistd.h> #include <time.h> #include <pwd.h> #include <private/android_filesystem_config.h> /* * SU can be given a specific command to exec. UID _must_ be * specified for this (ie argc => 3). * * Usage: * su 1000 * su 1000 ls -l */ int main(int argc, char **argv) { struct passwd *pw; int uid, gid, myuid; /* Until we have something better, only root and the shell can use su. */ myuid = getuid(); if (myuid != AID_ROOT && myuid != AID_SHELL) { fprintf(stderr,"su: uid %d not allowed to su\n", myuid); //return 1; } if(argc < 2) { uid = gid = 0; } else { pw = getpwnam(argv[1]); if(pw == 0) { uid = gid = atoi(argv[1]); } else { uid = pw->pw_uid; gid = pw->pw_gid; } } if(setgid(gid) || setuid(uid)) { fprintf(stderr,"su: permission denied\n"); //return 1; } /* User specified command for exec. */ if (argc == 3 ) { if (execlp(argv[2], argv[2], NULL) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } else if (argc > 3) { /* Copy the rest of the args from main. */ char *exec_args[argc - 1]; memset(exec_args, 0, sizeof(exec_args)); memcpy(exec_args, &argv[2], sizeof(exec_args)); if (execvp(argv[2], exec_args) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } /* Default exec shell. */ execlp("/system/bin/sh", "sh", NULL); fprintf(stderr, "su: exec failed\n"); return 1; }
HTML Link to an URL+Random number
<a href="http://lexra.pixnet.net/blog/post/289782841?1" onClick="this.href=this.href.split('?')[0]+'?'+new Date().getTime()">LINK</a>