📚
handbook
  • Introduction
  • 1.前言
    • 前言
    • 鸣谢
  • 2.环境篇
    • 工具部署和使用
      • 团队协作工具
        • Confluence
      • 开发工具
        • Docker
          • 镜像导入导出
          • 安装
        • Docker Compose
      • 持续集成工具
        • Gerrit
        • Sonarqube
          • 分析参数设定
          • Prerequisite
          • 服务端设置
        • Ubuntu Ci Deploy
          • ubuntu使用docker部署jenkins+sonarqube
        • 持续集成部署
      • 文本编辑工具
        • Gitbook相关注意事项
        • Markdown快速入门
      • 版本控制
        • Git
          • 1.基础
            • Git基础(一)
            • Git基础(二)
            • Git基础(三)
            • Git基础(四)
            • Git基础(五)
          • 2.命令详解
            • 命令速查
          • 3.进阶技巧
            • git技巧
      • 自动化测试工具
        • Appium
          • capability参数配置
          • 安装
          • 简介
      • 项目管理工具
        • Jira
    • 开发环境配置
      • 通用
        • Homebrew安装与使用
        • Git服务器添加SSH Key
        • koroFileHeader使用
        • nodejs与npm的安装
        • npm更换国内源
        • pip使用相关
        • PostgreSQL安装与使用
        • proxychain安装与使用
        • shell配置环境变量
        • snapd安装与使用
        • terminal走代理
    • 快捷键速查
      • shell常用快捷键
  • 3.语言篇
    • C
      • 代码规范
      • 语言技巧
    • Cpp
      • 代码规范
      • 基础知识
        • 理解C++中的左值和右值
      • 语言技巧
        • 并发编程
          • 简单的线程池实现
    • Golang
      • 代码规范
        • 避免使用转义字符串
        • 避免参数语义不明确
        • 嵌套式结构体
        • 函数的分组与顺序
        • 函数命名
        • 声明一致性
        • 导入别名
        • 使用字段名初始化结构体
        • 本地变量声明
        • map初始化
        • nil用法
        • 包命名
        • 命名Printf样式的函数
        • 减少嵌套
        • 缩小变量作用域
        • struct引用初始化
        • 测试表声明
        • 顶层变量声明
        • 不必要的else
      • 环境配置
        • 代码检查格式化工具
          • Go Fmt
          • Goimports
          • Golint
          • Go Vet
        • go mod详解
        • golang安装
        • Golang开发环境
        • Troubleshooting
      • 语言技巧
        • 如何分包
    • Java
      • 代码规范
      • 语言技巧
        • 注解编程
        • 动态代理
    • Js
      • 语言技巧
        • Rollup
    • Kotlin
      • 基础知识
        • 写给开发者Kotlin指引(一)
        • 写给开发者Kotlin指引(二)
    • Python
      • 语言技巧
        • Best Practice Of Python S Project Structure
  • 4.规范篇
    • Git message规范
  • 5.技术篇
    • Android技术
      • Hook
        • EdXposed例子
        • Android 10 上安装Magisk和EdXposed
      • Tinker
        • 1.Tinker及其使用
      • 准备
        • ADB连接设备步骤及注意事项
        • adb连接设备
        • aosp编译
      • 基础
        • Binder接口调用的鉴权方法
        • Make 及 Android 编译系统介绍
        • 使用Content Provider为其他应用提供数据
      • 源码阅读
        • Framework源码分析 Looper Handler
        • Framework源码分析 启动流程 ServiceManager的初始化
        • Framework源码分析 启动流程 Zygote启动SystemServer
    • JS Bridge
      • JSBridge初探
    • Kernel技术
      • kallsyms子系统
    • Test技术
      • 软件测试
        • jnekin+sonar 部署 问题总结
        • 性能测试基础
        • 软件测试的背景
        • 测试基础
        • 测试人员的核心竞争力
    • 操作系统原理
      • 处理器如何实现原子操作
Powered by GitBook
On this page
  • 综述
  • Coding

Was this helpful?

  1. 5.技术篇
  2. Android技术
  3. 基础

Binder接口调用的鉴权方法

综述

Binder鉴权的核心在于: 在Bn Service端获取接口调用者的信息,判断调用者是否满足权限条件。下面列举一个通过验证调用者证书的鉴权方法。

Coding

例子中包含一个Activity和一个Service,让它们分别运行在不同的进程中,AndroidManifest如下

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".SystemService"
            android:process=":SystemService"
            android:enabled="true"
            android:exported="true">
        </service>

然后声明一个aidl接口

// ISystemInterface.aidl
package com.wq.binderexample;

// Declare any non-default types here with import statements

interface ISystemInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    //void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
    //        double aDouble, String aString);
    String getWiFiSSID();
}

实现一个Service,这个Service在onBind方法中,返回上面aidl接口的实现

public class SystemService extends Service {
    private final String TAG = SystemService.class.getSimpleName();
    private final String[] PermittedSignatures = {
            "4LgyWU9gZ03bvH14X004K5fsVKqsJQAOj2lWmG5Fu64=",
    };

    private final ISystemInterface.Stub mInterface = new ISystemInterface.Stub() {
        @Override
        public String getWiFiSSID() throws SecurityException {
            if (checkPermission()) {
                return "hello";
            } else {
                throw new SecurityException("No Permission");
            }
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind");
        return mInterface;
    }
}

鉴权的核心在于checkPermission方法,如果鉴权通过则返回实际结果,如果鉴权失败则抛出异常。

    boolean checkPermission() {
        String callingApp = getBaseContext().getPackageManager().getNameForUid(Binder.getCallingUid());
        Log.i(TAG, "calling app: " + callingApp);

        try {
            Signature[] sis = getApplicationSignature(callingApp);
            final MessageDigest md = MessageDigest.getInstance("SHA256");
            for (Signature si : sis) {
                md.update(si.toByteArray());
                final String siBase64 = new String(Base64.encode(md.digest(), Base64.DEFAULT));
                Log.i(TAG,"Signature Base64: " + siBase64);
                for (String permittedSignature : PermittedSignatures) {
                    Log.i(TAG, "permittedSignature: " + permittedSignature);
                    if (permittedSignature.equals(siBase64.trim())) {
                        return true;
                    }
                }
            }
        } catch (java.security.NoSuchAlgorithmException e) {
            Log.e(TAG, "No MessageDigest Algorithm", e);
            return false;
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Can not find specific information", e);
            return false;
        }

        return false;
    }

    private Signature[] getApplicationSignature(String packageName) throws PackageManager.NameNotFoundException {
        Signature[] sig;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            sig = getSignatureBySigningInfo(packageName);
        } else {
            sig = getRawSignature(packageName);
        }

        return sig;
    }

    private Signature[] getRawSignature(String packageName) throws PackageManager.NameNotFoundException {
        if ((packageName == null) || (packageName.length() == 0)) {
            Log.e(TAG, "package name is error!");
            return null;
        }

        PackageManager pm = getBaseContext().getPackageManager();
        PackageInfo pi;
        pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
        if (pi == null) {
            Log.e(TAG, "Can not get package info, package name is: " + packageName);
            return null;
        }

        return pi.signatures;
    }

    private Signature[] getSignatureBySigningInfo(String packageName) throws PackageManager.NameNotFoundException {
        if ((packageName == null) || (packageName.length() == 0)) {
            Log.e(TAG, "package name is error!");
            return null;
        }

        PackageManager pm = getBaseContext().getPackageManager();
        PackageInfo pi;
        pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES);
        if (pi == null) {
            Log.e(TAG, "Can not get package info, package name is: " + packageName);
            return null;
        }

        return pi.signingInfo.getApkContentsSigners();
    }

checkPermission方法主要是通过获取调用者的UID,获取包信息中的签名,将签名sha256摘要后在转Base64字符串。通过对比这个字符串来判断调用者的签名是否符合要求。需要注意的是API 28以后GET_SIGNATURES方法被弃用,高版本需要通过GET_SIGNING_CERTIFICATES来获取apk签名。

简单看下调用端

public class MainActivity extends AppCompatActivity {
    private final String TAG = MainActivity.class.getSimpleName();
    /* protected by mLock */
    private final Object mLock = new Object();
    private static ISystemInterface mInterface;

    private Context mContext = App.getContext();
    private Button mButton;

    private ServiceConnection mConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.i(TAG, "System service has been connected!");

            synchronized (mLock) {
                mInterface = ISystemInterface.Stub.asInterface(iBinder);
                mLock.notify();
            }

            try {
                String ssid = mInterface.getWiFiSSID();
                Log.i(TAG, "ssid = " + ssid);
            } catch (RemoteException e) {
                Log.e(TAG, "call interface error!", e);
            } catch (SecurityException e) {
                Log.e(TAG, "Can not call remote interface", e);
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            synchronized (mLock) {
                mInterface = null;
            }

            Log.i(TAG, "System service has exited!");

            //rebind service
            Intent intent = new Intent(mContext, SystemService.class);
            mContext.bindService(intent, mConn, mContext.BIND_AUTO_CREATE);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.mButton);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.i(TAG, "Button click");

                // binder service
                synchronized (mLock) {
                    if (mInterface == null) {
                        //bind service
                        Log.i(TAG, "bind SystemService");
                        Intent intent = new Intent(mContext, SystemService.class);
                        mContext.bindService(intent, mConn, mContext.BIND_AUTO_CREATE);
                    }
                }

            }
        });
    }
}

这里的例子就是在push button的时候去bind service,在bind成功的回调中去调用接口。

Previous基础NextMake 及 Android 编译系统介绍

Last updated 4 years ago

Was this helpful?