Android Binder通信原理(八):IPC权限控制

news2024/12/23 10:30:49

源码基于:Android R

0. 前言

在之前的几篇博文中,对Android binder 的通信原理进行的深入的剖析,这些博文包括:binder 简介servicemanager启动service注册service获取Java 端的service 注册和获取、native下的C-Sjava 下的C-S

本文进一步分析 IPC 下的权限控制。

 

路径: 

frameworks/base/core/java/android/os/Binder.java

frameworks/base/core/jin/android_util_Binder.cpp

frameworks/native/libs/binder/IPCThreadState.cpp

1. java 代码

frameworks/base/core/java/android/os/Binder.java

public static final native long clearCallingIdentity();

public static final native void restoreCallingIdentity(long token);

2. JNI 代码

frameworks/base/core/jin/android_util_Binder.cpp

static jlong android_os_Binder_clearCallingIdentity()
{
    return IPCThreadState::self()->clearCallingIdentity();
}

static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
{
    // XXX temporary sanity check to debug crashes.
    int uid = (int)(token>>32);
    if (uid > 0 && uid < 999) {
        // In Android currently there are no uids in this range.
        char buf[128];
        sprintf(buf, "Restoring bad calling ident: 0x%" PRIx64, token);
        jniThrowException(env, "java/lang/IllegalStateException", buf);
        return;
    }
    IPCThreadState::self()->restoreCallingIdentity(token);
}

restore 参数 token 是clear接口的返回值。

3. IPCThreadState 中代码

frameworks/native/libs/binder/IPCThreadState.cpp

int64_t IPCThreadState::clearCallingIdentity()
{
    // ignore mCallingSid for legacy reasons
    int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
    clearCaller();
    return token;
}

void IPCThreadState::restoreCallingIdentity(int64_t token)
{
    mCallingUid = (int)(token>>32);
    mCallingSid = nullptr;  // not enough data to restore
    mCallingPid = (int)token;
}

clearCallingIdentity 主要两件事情:

  • 高32位为 mCallingUid,低32位为 mCallingPid,将其存放到 token,后面会通过restoreCallingIdentity() 恢复。
  • 调用 clearCaller(),临时获取 IPCThreadState 所在进程的确切PID 和 UID;
void IPCThreadState::clearCaller()
{
    mCallingPid = getpid();
    mCallingSid = nullptr;  // expensive to lookup
    mCallingUid = getuid();
}

4. 使用场景

  •  线程 A 通过 binder 调用到线程B,也有可能线程A 和线程B 在不同的进程;
  • 而线程B 中有这样的逻辑:
    •  组件一收到线程A 的调用后,这个时候线程B 所在的IPCThreadState 中的mCallingPid 和mCallingUid 可能会被修改,见4.2;
    • 当组件一调用组件二的功能时,想要显示组件一本身的PID 和UID,见4.1;
    • 当组件二完成后需要返回到组件一,需要恢复IPCThreadState 中的mCallingPid 和mCallingUid; 

 4.1 获取当前Bidner 线程的PID 和UID

JAVA:
public static final native int getCallingPid();
public static final native int getCallingUid();

JNI:
static jint android_os_Binder_getCallingPid()
{
    return IPCThreadState::self()->getCallingPid();
}
static jint android_os_Binder_getCallingUid()
{
    return IPCThreadState::self()->getCallingUid();
}

线程中可以通过Binder 接口获取calling pid 和calling uid,当然native 也可以通过IPCThreadState 获取:

pid_t IPCThreadState::getCallingPid() const
{
    return mCallingPid;
}
uid_t IPCThreadState::getCallingUid() const
{
    return mCallingUid;
}

那么最开始的mCallingPid 和mCallingUid 怎么来的呢?

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      ...
{
    ...
    clearCaller();
    ...
}

clearCaller() 在第 3 节解析过,这里在每一个Binder 线程创建的时候会获取当前线程所在的pid、uid。

4.2 IPCThreadState 作为接收端,会修改calling pid和uid

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    ...
    case BR_TRANSACTION:
        const pid_t origPid = mCallingPid;   //备份mCallingPid 和mCallingUid
        const char* origSid = mCallingSid;
        const uid_t origUid = mCallingUid;
        ...
        mCallingPid = tr.sender_pid;    //这里会修改成sender 的pid 和uid
        mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
        mCallingUid = tr.sender_euid;
        ...
        if (tr.target.ptr) {
            // We only have a weak reference on the target object, so we must first try to
            // safely acquire a strong reference before doing anything else with it.
            if (reinterpret_cast<RefBase::weakref_type*>(
                    tr.target.ptr)->attemptIncStrong(this)) {
                error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, //进入接收端,此时的pid和uid都为sender的
                        &reply, tr.flags);
                reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
            } else {
                error = UNKNOWN_TRANSACTION;
            }
        } else {
            error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
        }
        ...
        mCallingPid = origPid; //从接收端返回后,pid和uid 需要改为原始的
        mCallingSid = origSid;
        mCallingUid = origUid;
        ...
}

见代码中的注释,在 transact() 中都处于接收端,此时的 pid 和uid 都是sender 端的,如果此过程中需要获取Binder 原始的 mCallingPid 和mCallingUid,则需要调用clear和restore。

例如,AMS 中:

    public ComponentName startService(IApplicationThread caller, Intent service,
            ...
            String callingFeatureId, int userId)
            throws TransactionTooLargeException {
        ...
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, callingFeatureId, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }

在调用ActiveServices.startServiceLocked(),需要获悉当前线程PID 和UID,则需要在调用之前clear ,在调用返回后restore。

至此,IPC 权限控制分析完成。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/715791.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《QDebug 2023年6月》

一、Qt Widgets 问题交流 二、Qt Quick 问题交流 1.Qt5 的 QML Settings 没有设置编码的接口 Qt6 虽然移除了 QSettings 的 setIniCodec 接口&#xff0c;默认为 utf8&#xff0c;但是 Qt5 这个接口还能用&#xff0c;且没有默认 utf8。这就导致用 Qt5 QML 的 Settings 没法…

MAYA传送带上放石头(新旧粒子系统)

播放试试 使用老的粒子系统 particleShape1.shuliangrand(0,5); particleShape1.daxiao<<rand(0.2,0.5),rand(0.2,0.5),rand(0.2,0.5)>>; particleShape1.xuanzhuan<<rand(360),rand(360),rand(360)>>; 使用新的粒子系统 粒子向后滑落 新粒子系统能进行…

桥梁结构健康监测方案

一、方案背景 随着国民经济的快速发展&#xff0c;我国的基础设施建设得到蓬勃发展。桥梁作为国民生命财产安全的生命线&#xff0c;关系到国民经济和人民生活的可持续发展。在桥梁的长期运营过程中&#xff0c;存在施工缺陷、材料老化、自然环境以及荷载作用等原因造成桥梁结…

【Vue3】学习笔记-shallowReactive与ShallowRef

shallowReactive&#xff1a;只处理对象最外层属性的响应式&#xff08;浅响应式&#xff09;。 shallowRef&#xff1a;只处理基本数据类型的响应式, 不进行对象的响应式处理。 什么时候使用? 如果有一个对象数据&#xff0c;结构比较深, 但变化时只是外层属性变化 > sh…

【笔记】华南理工大学-智能计算方法 考试重点笔记 [非常详细]

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 目录 大纲 主观题 简答题 大纲 主观题 大题&#xff0c;40分&#xff0c;智能计算与自己专业方向结合&#xff0c;思路、图、公式等均可。 简答题

C/C++服务器和客户端交互笔记

C/C服务器开发 网络与通信Socket Socket通信三要素&#xff1a;通信的目的地址、使用的端口号&#xff08;http 80 / smtp 25&#xff09;、使用的传输协议&#xff08;TCP、UDP&#xff09;。 nslookup xx 可以查询xx网址的IP地址。 Socket通信模型 telnet ipxx 进行主机…

在ik分词器中自定义配置分词

找到ik分词器安装目录下的IKAnalyzer.cfg.xml配置文件 打开后就有让我们配置扩展字典的位置,还有停止的,这里的文件名完全自定义 当写完后然后再安装目录下创建这两个文件夹 在创建完成后重启elasticsearch即可 如果配置未生效很有可能是文件的编码格式有问题,我们将编码改为UT…

Linux-扩展篇-RPM和Yum-克隆和快照

扩展篇 学自尚硅谷武晟然老师&#xff0c;结合老师课堂内容和自己笔记所写博文。 文章目录 扩展篇软件包管理一、RPM1、RPM概述2、命令查询命令卸载命令安装命令 二、yum1、yum概述2、命令3、修改网络yum源 克隆虚拟机克隆快照 Shell编程Shell 概述 软件包管理 一、RPM 1、RP…

WIN11系统安装MySql8.0.15详细安装

一.下载mysql8.015数据库 下载地址&#xff1a; 如下图所示 此处下载的是8.0.15版本&#xff0c;免安装版&#xff0c;系统为64位系统&#xff1a; 二&#xff0c;配置mysql环境变量: D:\program_file_worker\mysql8.15\mysql-8.0.15-winx64\bin 三. 环境配置完成后&#xff…

优化设备管理,半导体CMS系统的重要性和优势解析

在半导体制造行业中&#xff0c;设备管理对于企业的生产效率和成本控制起着至关重要的作用。随着技术的不断进步和市场的竞争加剧&#xff0c;企业需要更加精细化、智能化地管理设备&#xff0c;以提高生产效率、降低维修成本&#xff0c;并确保产品质量的稳定性。 图.半导体芯…

vue 对话框内容超出组件问题

遇到这种问题该怎么解决, 样式问题 很好解决 解决方案很简单: 用flex布局的flex-wrap: wrap 数据 自适应布局 水了一篇 哈哈哈

管理类联考——数学——趣味篇——公式——图形推导

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&…

SNMP 计算机网络管理 实验1(三) 练习与使用Wireshark抓取SNMP数据包抓包之任务四 分析并验证ARP协议数据单元的格式;

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

【python】__init__.py 文件的作用

先看文件夹组成&#xff1a; 可以看到&#xff0c;几乎每个文件夹下都有__init__.py&#xff0c;一个目录如果包含了__init__.py 文件&#xff0c;那么它就变成了一个包&#xff08;package&#xff09;。__init__.py可以为空&#xff0c;也可以定义包的属性和方法&#xff0…

Java开发 - Canal进阶之和Redis的数据同步

前言 Canal在数据同步中是非常常见的&#xff0c;一般我们会用它来做MySQL和Redis之间、MySQL和ES之间的数据同步&#xff0c;否则就是手动通过代码进行同步&#xff0c;造成代码耦合度高的问题&#xff0c;这并不是我们愿意看见的&#xff0c;今天这篇博客博主将给大家演示Ca…

速下载|2023上半年网络与数据安全法规政策、国标、报告合集

随着国家数字经济建设进程加快&#xff0c;数据安全立法实现由点到面、由面到体加速构建&#xff0c;目前我国数据安全立法已基本形成以《网络安全法》《数据安全法》《个人信息保护法》《密码法》等法律为核心&#xff0c;行政法规、部门规章为依托&#xff0c;地方性法规、地…

【全文搜索选型】全文搜索 PostgreSQL 或 ElasticSearch

在本文中&#xff0c;我记录了在 PostgreSQL&#xff08;使用 Django ORM&#xff09;和 ElasticSearch 中实现全文搜索 (FTS) 时的一些发现。 作为一名 Django 开发人员&#xff0c;我开始寻找可用的选项来在大约一百万行的标准大小上执行全文搜索。有两个值得尝试的选项&…

百度文心一言App已在AppStore上架—特别是发现页的功能太强大了

百度文心一言 App 现已上架苹果 App Store&#xff0c;所有用户可免费下载安装。 特别是发现页的功能&#xff0c;真的太强大了&#xff0c;基本涵盖了你所有已知的 AI 工具功能&#xff01;比如&#xff1a; 小红书探店文案、风格头像、朋友圈神器、短视频脚本生成、AI 绘画…

【ESP32 开发】| Clion 搭建 ESP32 开发环境

目录 前言1 软件以及所需工具2 安装 ESP-IDF 4.4.42.1 开始安装2.2 选择组件&#xff0c;建议全选 3 用 ESP-IDF 4.4 CMD 添加环境变量并新建工程3.1 打开 ESP-IDF 4.4 CMD 初始化环境变量3.2 切到工作路径并新建工程 4 配置 Clion 开发环境4.1 用 Clion 打开新建的工程文件4.2…

有了企业网盘,为什么要需要知识文档管理系统

关键词&#xff1a;企业网盘、知识文档管理系统、群晖NAS 编者按&#xff1a;随着企业办公室自动化的要求越来越明显&#xff0c;企业对于文档存储的需求也逐渐加大。企业网盘的出现解决了公司文件数据储存等难题。但随着企业的文档数据逐渐增多&#xff0c;如何安全管理企业重…