Android6.0以上獲取前臺進程的方法

原文地址:http://www.jianshu.com/p/43078a0c18e5

今天遇到個問題, 使用action爲“Android.media.action.IMAGE_CAPTURE“打不開Android6.0系統的小米4手機照相機, 問題是你不知道到底是否啓動了相機。 我試了很多種方法, 最終只想到一個土辦法:點擊拍照按鈕後延遲1秒判斷是否執行了onStop函數或自己是否前臺進程,方法很low也可能誤判。(PS:從自己app打開照相機後會執行onPause-onStop函數)但在嘗試的過程中學到不少東西, 可以分享一下:        目前沒找到6.0版本獲取top activity的方法, google把我能想到的路都封死了。 因爲這是個漏洞,假設釣魚app監聽打開支付寶、微信輸入密碼的activity時,覆蓋一模一樣的界面就可以盜取你的機密信息了。 1、 Android5.0以下的方法在5.0及後續版本不再有效。

List tasks = am.getRunningTasks(1);

if (tasks != null && !tasks.isEmpty()) {

ComponentName componentName = tasks.get(0).topActivity;

if (componentName != null) {

return componentName.getClassName();

}

}

2、嘗試ActivityManager的getRunningAppProcesses方法,但從Andriod5.1版本後只能拿到自己的進程信息, 所以此路不通;

3、使用UsageStatsManager類驗證, 但它需要系統權限, 實際使用場景下很難被授權, 此路不通;

4、思路:在Android Runtime運行dumpsys meminfo , 拿到輸出並截取前臺進程, 但是拿不到top activity, 可以做個測試手段。

在cmd窗口執行adb shell dumpsys meminfo 後輸出所有運行進程的信息,能明顯的看出那個是前臺進程。 但在Android運行時報無DUMP權限, 這是系統簽名才能執行的操作。

373663 kB:      0 kB: Foreground

265450 kB:      0 kB: com.android.browser (pid 9131 / activities)

30164 kB:      0 kB: com.miui.securitycenter.remote (pid 3191)

28803 kB:      0 kB: com.miui.networkassistant.deamon (pid 3125)

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片

do_exec("dumpsys meminfo ");

String do_exec(String cmd) {

String s = "/n";

try {

Process p = Runtime.getRuntime().exec(cmd);

BufferedReader in = new BufferedReader(

new InputStreamReader(p.getInputStream()));

String line = null;

while ((line = in.readLine()) != null) {

s += line + "/n";

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return s;

}

5、hook AMS, 能夠監聽到打開照相機的action,但無法確定是否啓動了照相機。 原理是隻能hook ActivityManagerNative類,是ActivityManagerService的代理對象,運行在app當前進程;無法hook AMS的本地對象(運行在system_server進程)。

6、嘗試打開手機proc目錄下進程id目錄下的cmdline文件, 部分機型能夠看到包名。如果是前臺進程,那麼oom_score_adj文件內容爲0;否則不是0。 而cmdline文件中是對應的包名。  因爲Linux限制打開其它進程的文件,無法讀取其它進程目錄下的cmdline和oom_adj文件, 但可以瞭解一下Linux命令。

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片

private String getForegroundApp() {

File[] files = new File("/proc").listFiles();

String foregroundProcess = null;

int i = 0;

for (File file : files) {

i++;

Log.d("brycegao", "proc file:" + file.getName()

+ ", loop:" + i);

if (file.isFile()) {

continue;

}

int pid;

Log.d("brycegao", "proc filename:" + file.getName());

try {

pid = Integer.parseInt(file.getName());

} catch (NumberFormatException e) {

continue;

}

try {

//讀取進程名稱

String cmdline = read(String.format("/proc/%d/cmdline", pid));

String oomAdj = read(String.format("/proc/%d/oom_score_adj", pid));

Log.d("brycegao", "adj1111:" + oomAdj + ",pkg:" + cmdline);

if (oomAdj.equalsIgnoreCase("0")) {

//前臺進程

Log.d("brycegao", "adj:" + oomAdj + ",pkg:" + cmdline);

} else {

continue;

}

if (cmdline.contains("systemui")

|| cmdline.contains("/")) {

continue;

}

foregroundProcess = cmdline;

} catch (IOException e) {

e.printStackTrace();

}

}

return foregroundProcess;

}

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片

private String read(String path) throws IOException {

StringBuilder output = new StringBuilder();

BufferedReader reader = new BufferedReader(new FileReader(path));

output.append(reader.readLine());

for (String line = reader.readLine(); line != null; line = reader.readLine()) {

output.append('\n').append(line);

}

reader.close();

return output.toString();

}

7、嘗試使用linux 的ps命令、grep命令和cat命令, 驚訝的發現使用cat可以查看其它進程目錄下的文件!!! 對上面方法稍作改變,就能得到前臺進程的名稱了, 注意前臺進程是多個。 下面的示例代碼只取一個前臺進程名稱, 其實應該是個ArrayList,懶的優化了、只說原理。 其實就是將打開文件的操作改成用cat查看, 這樣就不會出現權限問題了。

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片

private String getForegroundApp() {

File[] files = new File("/proc").listFiles();

String foregroundProcess = "";

int i = 0;

for (File file : files) {

i++;

Log.d("brycegao", "proc file:" + file.getName()

+ ", loop:" + i);

if (file.isFile()) {

continue;

}

int pid;

Log.d("brycegao", "proc filename:" + file.getName());

try {

pid = Integer.parseInt(file.getName());

} catch (NumberFormatException e) {

continue;

}

try {

//讀取進程名稱

String cmdline = do_exec(String.format("cat /proc/%d/cmdline", pid));

String oomAdj = do_exec(String.format("cat /proc/%d/oom_adj", pid));

Log.d("brycegao", "adj1111:" + oomAdj + ",pkg:" + cmdline);

if (oomAdj.equalsIgnoreCase("0")) {

//前臺進程

Log.d("brycegao", "adj:" + oomAdj + ",pkg:" + cmdline);

} else {

continue;

}

if (cmdline.contains("systemui")

|| cmdline.contains("/")) {

continue;

}

foregroundProcess = cmdline;

} catch (Exception e) {

e.printStackTrace();

}

}

Log.d("brycegao", "forgroud process:" + foregroundProcess);

return foregroundProcess;

}

第7個方法算是個黑科技了, 能拿到Android手機的前臺進程名稱(注意:前臺進程可以是多個), 但無法判斷當前正在顯示的是哪個進程以及top activity。。。。

http://blog.csdn.net/brycegao321/article/details/53414019

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章