IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> [Android实战笔记] 获取应用的pid、uid、packageName、进程名 -> 正文阅读

[移动开发][Android实战笔记] 获取应用的pid、uid、packageName、进程名

目录

pid

1.通过api调用获取:[需要在应用内调用]

uid?

1. 通过api调用获取:[需要在应用内调用]

2.通过反射调用:Process.getUidForPid(int pid);

进程名(/包名)

1. 通过api调用获取:Application.getProcessName(); [需要在应用内调用]

2.通过反射调用:ActivityThread.currentProcessName();? [需要在应用内调用]

3. 通过AMS获取

4.根据pid通过反射调用:Process.readProcLines(String path, String[] reqFields, long[] outSizes)

5.根据pid通过proc节点获取 [可在native层使用]


pid

1.通过api调用获取:[需要在应用内调用]

int pid = android.os.Process.myPid();

uid?

1. 通过api调用获取:[需要在应用内调用]

int pid = android.os.Process.myUid();

2.通过反射调用:Process.getUidForPid(int pid);

/** @hide */

public static final int getUidForPid(int pid);

进程名(/包名)

* 注:一般来说未指定的进程名和包名是一致的。对于一些多进程应用,该应用下的多个进程名一般为:包名:指定进程后缀。?

1. 通过api调用获取:Application.getProcessName(); [需要在应用内调用]

public static String getProcessName();

弊端:SDK28才增加了这个api,只有在Android 9 以上的系统才可以使用

public static String getCurrentProcessNameByApplication() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        return Application.getProcessName();
    }
    return null;
}

2.通过反射调用:ActivityThread.currentProcessName();? [需要在应用内调用]

/** @hide */

public static String currentProcessName();

弊端:ActivityThread这个类是 @hide 的,app无法直接调用。但是可以通过反射的方式实现。

public static String getCurrentProcessNameByActivityThread() {
    String processName = null;
    try {
        final Method declaredMethod = Class.forName("android.app.ActivityThread", false, Application.class.getClassLoader()).getDeclaredMethod("currentProcessName", (Class<?>[]) new Class[0]);
        declaredMethod.setAccessible(true);
        final Object invoke = declaredMethod.invoke(null, new Object[0]);
        if (invoke instanceof String) {
            processName = (String) invoke;
        }
    } catch (Throwable e) {
    }
    return processName;
}

3. 通过AMS获取

public static String getCurrentProcessNameByActivityManager(@NonNull Context context) {
    int pid = Process.myPid();
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    if (am != null) {
        List<ActivityManager.RunningAppProcessInfo> runningAppList = am.getRunningAppProcesses();
        if (runningAppList != null) {
            for (ActivityManager.RunningAppProcessInfo processInfo : runningAppList) {
                if (processInfo.pid == pid) {
                    return processInfo.processName;
                }
            }
        }
    }
    return null;
}

* RunningAppProcessInfo 中还有 pid 、uid 等信息,同样可以用于比对获取 pid 和 uid。

弊端:通过AIDL跨进程方式调用 + for遍历,效率不高;AIDL可能调用失败。

4.根据pid通过反射调用:Process.readProcLines(String path, String[] reqFields, long[] outSizes)

/** @hide */

public static final native void readProcLines(String path, String[] reqFields, long[] outSizes);

linux中对所有应用都有对应的proc节点记录各种信息。proc/(pid)/status 记录了对应pid的应用的所有信息,包括uid、ppid、组信息等。Process类中封装了一个readProcLines的方法去读取 proc/(pid)/status 文件的信息,具体使用方式可以参考 Process类中的 getUidForPid(pid)、getParentPid(pid) 、 getThreadGroupLeader(tid) 。?

弊端:IO操作,可能影响性能

5.根据pid通过proc节点获取 [可在native层使用]

native 层暂未发现api,但是可以参考上一点的方式去实现。由于 linux 中一切皆文件,因此用读取文件的方式即可解决。

status_t getPackageNameFromPid(int pid, String8& packageName)
{
    status_t status = NO_ERROR;
    int ret;
    char cmdline[256] = {0};
    char buf[256] = {0};
    snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
    int fd = 0;
    fd = open(cmdline, O_RDONLY);
    if (fd < 0)
    {
        status = NAME_NOT_FOUND;
    } else {
        ret = read(fd, buf, sizeof(buf));
        if (ret <= 0)
        {
            status = BAD_VALUE;
        }
    }
    close(fd);
    if (status != NO_ERROR) {
        return status;
    }
    
    // 以上是获取了进程名,获取包名需要进一步截取
    String8 processName = String8(buf);
    ssize_t index = processName.find(":", 0);
    if (index >= 0) {
        packageName.clear();
        packageName.setTo(processName, index);
    } else {
        packageName = processName;
    }
    return status;
}

* 注:在native层调用时可能会读取文件失败,错误信息:

errno = ENOENT? ?????????/* No such file or directory */

由于笔者在系统开发中有获取包名的需求,使用以上实现时出现读取文件失败的问题。经过开启 kernel 打印进行调用,排除了selinux的权限问题之后,发现是需要对读取proc的进程赋予权限才可实现。因此在对应进程的rc文件中赋予权限即可。

service audioserver /system/bin/audioserver
? ? class main
? ? user audioserver
? ? # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
? ? group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct readproc
? ? ioprio rt 4
? ? writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
? ? onrestart restart audio-hal-2-0

* 注:如果需要判断多个进程是否属于同一应用,可以通过一下两种方式确认:

1. 对于非系统应用(未指定应用shareUserId为“android.uid.system”),只需要比对进程的uid是否一致即可。对于指定了shareUserId为“android.uid.system”的应用,他们将共享UID为1000。

2. 通过pid -> 进程名 -> 包名的方式进行包名比对。若包名一致,则属于同一应用。

参考资料:https://juejin.cn/post/6877127949452050446

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-03 11:19:29  更:2021-08-03 11:21:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/6 2:06:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码