Android如何监听第三方应用的启动
来源:互联网 发布:php分页代码兄弟连 编辑:程序博客网 时间:2024/05/21 22:23
个人总结的监听第三方应用启动的方法有以下几种:
1.Root状态下Shell监听ActivityManager的log,或者ps进程
2.参考程序锁的实现,监听后台运行的进程
3.深入framework,通过反射等方式注入hook
第一种方式监听应用的启动,restart都能监控到,不过这种方式限制很大,在最新的android版本中,再加上各手机厂商对于安全性的努力,使得Root变的很困难。
第二种方式采用不断轮询的方式检查后台进程,个人以为这样非常的耗费性能,时间间隔长的话实时性又无法保证。所以最佳的方式还是采用监听的方式,向ActivityManagerService中设置一个监听,用户启动应用都会通知。
第三种方案看起来是最佳方案,不过它需要系统权限,实现类似monkey的功能,setActivityController这个方法设置IActivityController接口。
package android.app;import android.content.Intent;/** * Testing interface to monitor what is happening in the activity manager * while tests are running. Not for normal application development. * {@hide} */interface IActivityController{ /** * The system is trying to start an activity. Return true to allow * it to be started as normal, or false to cancel/reject this activity. */ boolean activityStarting(in Intent intent, String pkg); /** * The system is trying to return to an activity. Return true to allow * it to be resumed as normal, or false to cancel/reject this activity. */ boolean activityResuming(String pkg); /** * An application process has crashed (in Java). Return true for the * normal error recovery (app crash dialog) to occur, false to kill * it immediately. */ boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, long timeMillis, String stackTrace); /** * Early call as soon as an ANR is detected. */ int appEarlyNotResponding(String processName, int pid, String annotation); /** * An application process is not responding. Return 0 to show the "app * not responding" dialog, 1 to continue waiting, or -1 to kill it * immediately. */ int appNotResponding(String processName, int pid, String processStats); /** * The system process watchdog has detected that the system seems to be * hung. Return 1 to continue waiting, or -1 to let it continue with its * normal kill. */ int systemNotResponding(String msg);}IActivityController.aidl的接口可以很容易监听每个process。
综上,普通APP开发,在没有root和系统权限的支持下,就只能老老实实的用第二种方案了,但是。。。Android 5.0之后对于ActivityManager获取的RunningTask,RunningProcess,RunningServiceInfo等又有了诸多限制。
既然Android 5.0之后ActivityManager获取的信息稀少了,我们不如换一种思路,不再依赖ActivityManager,转而去分析根目录下额proc目录,这个proc目录是干什么的?
/proc是一个虚拟文件系统,其下面的文件不是真实存在的,不占用实际存储空间。/proc/cmdline:显示内核启动的命令行。/proc/cpuinfo:显示系统cpu的信息。/proc/filesystems,显示当前注册了的文件系统列表,nodev表示为虚拟文件系统。/proc/interrupts:显示当前系统的中断信息./proc/ioports:被占用的输入/输出地址范围列表。/proc/kmsg:输出内核消息日志。/proc/loadavg:监控cpu平均负载,其数值为所有核上cpu占用的累加值,前三个分别表示最近1、5、15分钟的平均负载,第四个表示当前运行进程数和进程总数,最后一个表示最近运行的进程id。/proc/locks:打开文件上的加锁信息。/proc/meminfo:显示物理及虚拟内存使用情况。/proc/misc:内核函数misc_register登记的设备驱动程序。/proc/modules:加载的内核模块列表。Proc/mounts:当前系统所安装的文件系统信息(包括手动安装的)。/proc/stat:系统简要信息。/proc/uptime:分别表示系统启动时间和系统空闲时间。/proc/version:系统内核版本。/proc/net:其实际挂载点是/proc/self/net,能够显示当前各种网络情况,例如通过tcp文件可以查看tcp连接数及连接情况。/proc/sys 报告各种不同的内核参数,某些参数能在root的情况下进行修改。/Proc/devices 当前挂载的所有软硬件设备(字符设备和块设备),包括主设备号和设备名称。/proc/asound:声卡相关的信息。/proc/buddyinfo:每个内存区中每个order有多少块可用,和内存碎片问题有关。/proc/bus:输入设备信息。/proc/cgroups:查看cgroups子系统信息。/proc/diskstats:用于显示磁盘、分区和统计信息。/proc/execdomains:安全相关的信息。/proc/fb:帧缓冲设备信息。/proc/iomem:记录物理地址的分配情况。/proc/kallsyms:内核符号表信息。/proc/pagetypeinfo:内存分页信息。/proc/partitions:分区信息/proc/sched_debug:cpu调度信息。/proc/softirqs:软中断情况。/proc/vmallocinfo:vmalloc内存分配信息。/proc/vmstat:统计虚拟内存信息。/proc/pid:显示进城相关的所有信息。
/* * Copyright (C) 2015. Jared Rummler <jared.rummler@gmail.com> * * 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. * */package com.jaredrummler.android.processes.models;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.Parcel;import java.io.IOException;public class AndroidAppProcess extends AndroidProcess { /** {@code true} if the process is in the foreground */ public boolean foreground; /** The user id of this process. */ public int uid; private final Cgroup cgroup; public AndroidAppProcess(int pid) throws IOException, NotAndroidAppProcessException { super(pid); cgroup = super.cgroup(); ControlGroup cpuacct = cgroup.getGroup("cpuacct"); ControlGroup cpu = cgroup.getGroup("cpu"); if (cpu == null || cpuacct == null || !cpuacct.group.contains("pid_")) { throw new NotAndroidAppProcessException(pid); } foreground = !cpu.group.contains("bg_non_interactive"); try { uid = Integer.parseInt(cpuacct.group.split("/")[1].replace("uid_", "")); } catch (Exception e) { uid = status().getUid(); } } /** * @return the app's package name * @see #name */ public String getPackageName() { return name.split(":")[0]; } /** * Retrieve overall information about the application package. * * <p>Throws {@link PackageManager.NameNotFoundException} if a package with the given name can * not be found on the system.</p> * * @param context * the application context * @param flags * Additional option flags. Use any combination of * {@link PackageManager#GET_ACTIVITIES}, {@link PackageManager#GET_GIDS}, * {@link PackageManager#GET_CONFIGURATIONS}, {@link PackageManager#GET_INSTRUMENTATION}, * {@link PackageManager#GET_PERMISSIONS}, {@link PackageManager#GET_PROVIDERS}, * {@link PackageManager#GET_RECEIVERS}, {@link PackageManager#GET_SERVICES}, * {@link PackageManager#GET_SIGNATURES}, {@link PackageManager#GET_UNINSTALLED_PACKAGES} * to modify the data returned. * @return a PackageInfo object containing information about the package. */ public PackageInfo getPackageInfo(Context context, int flags) throws PackageManager.NameNotFoundException { return context.getPackageManager().getPackageInfo(getPackageName(), flags); } @Override public Cgroup cgroup() { return cgroup; } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeParcelable(cgroup, flags); dest.writeByte((byte) (foreground ? 0x01 : 0x00)); } protected AndroidAppProcess(Parcel in) { super(in); cgroup = in.readParcelable(Cgroup.class.getClassLoader()); foreground = in.readByte() != 0x00; } public static final Creator<AndroidAppProcess> CREATOR = new Creator<AndroidAppProcess>() { @Override public AndroidAppProcess createFromParcel(Parcel source) { return new AndroidAppProcess(source); } @Override public AndroidAppProcess[] newArray(int size) { return new AndroidAppProcess[size]; } }; public static final class NotAndroidAppProcessException extends Exception { public NotAndroidAppProcessException(int pid) { super(String.format("The process %d does not belong to any application", pid)); } }}
AndroidAppProcess根据proc信息解析出forceground、uid、packageName等信息,我们再看看基类AndroidProcess
/* * Copyright (C) 2015. Jared Rummler <jared.rummler@gmail.com> * * 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. * */package com.jaredrummler.android.processes.models;import android.os.Parcel;import android.os.Parcelable;import android.text.TextUtils;import java.io.IOException;public class AndroidProcess implements Parcelable { /** * Get the name of a running process. * * @param pid * the process id. * @return the name of the process. * @throws IOException * if the file does not exist or we don't have read permissions. */ static String getProcessName(int pid) throws IOException { String cmdline = null; try { cmdline = ProcFile.readFile(String.format("/proc/%d/cmdline", pid)).trim(); } catch (IOException ignored) { } if (TextUtils.isEmpty(cmdline) || "null".equals(cmdline)) { return Stat.get(pid).getComm(); } return cmdline; } /** the process name */ public final String name; /** the process id */ public final int pid; /** * AndroidProcess constructor * * @param pid * the process id * @throws IOException * if /proc/[pid] does not exist or we don't have read access. */ public AndroidProcess(int pid) throws IOException { this.pid = pid; this.name = getProcessName(pid); } /** * Read the contents of a file in /proc/[pid]/[filename]. * * @param filename * the relative path to the file. * @return the contents of the file. * @throws IOException * if the file does not exist or we don't have read permissions. */ public String read(String filename) throws IOException { return ProcFile.readFile(String.format("/proc/%d/%s", pid, filename)); } /** * @return the contents of /proc/[pid]/attr/current * @throws IOException * if the file does not exist or we don't have read permissions. */ public String attr_current() throws IOException { return read("attr/current"); } /** * <p>/proc/[pid]/cmdline</p> * * <p>This read-only file holds the complete command line for the process, unless the process is * a zombie. In the latter case, there is nothing in this file: that is, a read on this file will * return 0 characters. The command-line arguments appear in this file as a set of strings * separated by null bytes ('\0'), with a further null byte after the last string.</p> * * @return the name of the process. (note: process name may be empty. In case it is empty get * the process name from /proc/[pid]/stat). * @throws IOException * if the file does not exist or we don't have read permissions. * @see #name */ public String cmdline() throws IOException { return read("cmdline"); } /** * @return the {@link Cgroup} for this process * @throws IOException */ public Cgroup cgroup() throws IOException { return Cgroup.get(pid); } /** * @return the oom_adj value for this process * @throws IOException * if the file does not exist or we don't have read permissions. */ public int oom_adj() throws IOException { return Integer.parseInt(read("oom_adj")); } /** * @return the oom_score_adj value for this process * @throws IOException * if the file does not exist or we don't have read permissions. */ public int oom_score_adj() throws IOException { return Integer.parseInt(read("oom_score_adj")); } /** * @return the {@link Stat} for this process * @throws IOException * if the file does not exist or we don't have read permissions. */ public Stat stat() throws IOException { return Stat.get(pid); } /** * @return the {@link Statm} for this process * @throws IOException * if the file does not exist or we don't have read permissions. */ public Statm statm() throws IOException { return Statm.get(pid); } /** * @return the {@link Status} for this process * @throws IOException * if the file does not exist or we don't have read permissions. */ public Status status() throws IOException { return Status.get(pid); } /** * The symbolic name corresponding to the location in the kernel where the process is sleeping. * * @return the contents of /proc/[pid]/wchan * @throws IOException * if the file does not exist or we don't have read permissions. */ public String wchan() throws IOException { return read("wchan"); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.name); dest.writeInt(this.pid); } protected AndroidProcess(Parcel in) { this.name = in.readString(); this.pid = in.readInt(); } public static final Creator<AndroidProcess> CREATOR = new Creator<AndroidProcess>() { @Override public AndroidProcess createFromParcel(Parcel source) { return new AndroidProcess(source); } @Override public AndroidProcess[] newArray(int size) { return new AndroidProcess[size]; } };}AndroidProcess解析了pid,process name等信息
参考文章:
http://blog.csdn.net/anlegor/article/details/38317305
http://www.cnblogs.com/luoyangcn/p/4936830.html
github地址:
https://github.com/jaredrummler/AndroidProcesses
- Android如何监听第三方应用的启动
- Android---启动第三方应用
- Android 启动第三方应用
- Android 第三方应用监听home键
- Android在自己的应用中启动第三方应用
- Android应用内启动第三方应用
- Android 应用内启动第三方应用
- Android-PackageManager与startActivity启动第三方应用的Activity
- android-code-启动第三方应用
- android 关联启动第三方应用
- Android启动早于系统应用的第三方应用,杀不死自动重启的第三方应用
- Android启动早于系统应用的第三方应用,杀不死自动重启的第三方应用
- Android中如何启动第三方程序?
- Android中如何启动第三方程序
- Android监听进入和退出第三方应用
- 启动第三方或系统的应用
- 获取android已安装的应用PackageInfo启动第三方APP应用
- android 启动第三方程序的代码
- 用Device tree overlay掌控Beaglebone Black的硬件资源
- 有错误的代码 下机回去改
- ByteArrayInputStream:源:内存 ByteArrayOutputStream:目的:内存。
- java的echarts完整
- TCP和UDP代码示意
- Android如何监听第三方应用的启动
- 使用Rserve远程执行R脚本
- vue2.0——运动
- 捕捉信号SIGSEGV并回溯栈帧
- 9. Palindrome Number
- prettytensor 的使用
- Android开发--TableLayout中加载自写xml格式图形虚拟机上可显示,真机显示不了
- jquery radio取值,checkbox取值,select取值,radio选中,checkbox选中,select选中,及其相关
- LINUX core dump详解 & GDB调试