在 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>
