今天遇到個(gè)問(wèn)題拢切, 使用action為“Android.media.action.IMAGE_CAPTURE“打不開(kāi)Android6.0系統(tǒng)的小米4手機(jī)照相機(jī)赊瞬, 問(wèn)題是你不知道到底是否啟動(dòng)了相機(jī)斜做。 我試了很多種方法, 最終只想到一個(gè)土辦法:點(diǎn)擊拍照按鈕后延遲1秒判斷是否執(zhí)行了onStop函數(shù)或自己是否前臺(tái)進(jìn)程略水,方法很low也可能誤判徽诲。(PS:從自己app打開(kāi)照相機(jī)后會(huì)執(zhí)行onPause-onStop函數(shù))但在嘗試的過(guò)程中學(xué)到不少東西, 可以分享一下:? ? ? ? 目前沒(méi)找到6.0版本獲取top activity的方法牡属, google把我能想到的路都封死了票堵。 因?yàn)檫@是個(gè)漏洞,假設(shè)釣魚app監(jiān)聽(tīng)打開(kāi)支付寶逮栅、微信輸入密碼的activity時(shí)悴势,覆蓋一模一樣的界面就可以盜取你的機(jī)密信息了。 1措伐、 Android5.0以下的方法在5.0及后續(xù)版本不再有效特纤。
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版本后只能拿到自己的進(jìn)程信息捧存, 所以此路不通;
3官硝、使用UsageStatsManager類驗(yàn)證矗蕊, 但它需要系統(tǒng)權(quán)限, 實(shí)際使用場(chǎng)景下很難被授權(quán)氢架, 此路不通傻咖;
4、思路:在Android Runtime運(yùn)行dumpsys meminfo 岖研, 拿到輸出并截取前臺(tái)進(jìn)程卿操, 但是拿不到top activity, 可以做個(gè)測(cè)試手段孙援。
在cmd窗口執(zhí)行adb shell dumpsys meminfo 后輸出所有運(yùn)行進(jìn)程的信息害淤,能明顯的看出那個(gè)是前臺(tái)進(jìn)程。 但在Android運(yùn)行時(shí)報(bào)無(wú)DUMP權(quán)限拓售, 這是系統(tǒng)簽名才能執(zhí)行的操作窥摄。
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础淤, 能夠監(jiān)聽(tīng)到打開(kāi)照相機(jī)的action崭放,但無(wú)法確定是否啟動(dòng)了照相機(jī)。 原理是只能hook ActivityManagerNative類鸽凶,是ActivityManagerService的代理對(duì)象币砂,運(yùn)行在app當(dāng)前進(jìn)程;無(wú)法hook AMS的本地對(duì)象(運(yùn)行在system_server進(jìn)程)玻侥。
6决摧、嘗試打開(kāi)手機(jī)proc目錄下進(jìn)程id目錄下的cmdline文件, 部分機(jī)型能夠看到包名。如果是前臺(tái)進(jìn)程掌桩,那么oom_score_adj文件內(nèi)容為0边锁;否則不是0。 而cmdline文件中是對(duì)應(yīng)的包名拘鞋。? 因?yàn)長(zhǎng)inux限制打開(kāi)其它進(jìn)程的文件砚蓬,無(wú)法讀取其它進(jìn)程目錄下的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 {
//讀取進(jìn)程名稱
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")) {
//前臺(tái)進(jìn)程
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命令隔躲, 驚訝的發(fā)現(xiàn)使用cat可以查看其它進(jìn)程目錄下的文件!N镅印宣旱! 對(duì)上面方法稍作改變,就能得到前臺(tái)進(jìn)程的名稱了叛薯, 注意前臺(tái)進(jìn)程是多個(gè)浑吟。 下面的示例代碼只取一個(gè)前臺(tái)進(jìn)程名稱, 其實(shí)應(yīng)該是個(gè)ArrayList耗溜,懶的優(yōu)化了组力、只說(shuō)原理。 其實(shí)就是將打開(kāi)文件的操作改成用cat查看抖拴, 這樣就不會(huì)出現(xiàn)權(quán)限問(wèn)題了燎字。
[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 {
//讀取進(jìn)程名稱
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")) {
//前臺(tái)進(jìn)程
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個(gè)方法算是個(gè)黑科技了, 能拿到Android手機(jī)的前臺(tái)進(jìn)程名稱(注意:前臺(tái)進(jìn)程可以是多個(gè))阿宅, 但無(wú)法判斷當(dāng)前正在顯示的是哪個(gè)進(jìn)程以及top activity候衍。。洒放。蛉鹿。
http://blog.csdn.net/brycegao321/article/details/53414019