Servicemanager

源码在/frameworks/base/cmds/servicemanager/service_manager.c

编译成 systemmanager 可执行文件

systemmanager是以binder为主要通信手段,为系统各种各样服务的进行登记查询管理的服务。

系统服务的框架里有3个主要角色,服务提供者(server),服务使用者(client),和服务管理者(system manager),通信方式是Binder,在系统启动流程中的先后顺序是:服务管理者,服务提供者,服务使用者。

成为system manager

该进程会常驻在系统中,先通过binder_become_context_manager()注册为系统中服务管理器(本质上是通过ioctl对打开的/dev/binder的fd发送BINDER_SET_CONTEXT_MGR),然后通过binder_loop() 进入死循环,来持续为系统系统各种服务的查询/添加功能。各个服务本身运行在自己的进程中,但是通过systemmanager这样一个枢纽,提供真实服务的进程,将自己的服务向systemmanager注册,然后其他需要使用服务的进程通过先从/dev/binder中获取到systemmanager,然后再通过systemmanager查询并获取到真正想要的服务的stub,然后包装成binderPoxy(bpbinder),然后通过这个bpbinder与真正的服务进行IPC通信。

用在服务提供者和服务使用者角色中,与system manager 进行通信的模块:IPCThreadState 和 ProcessState

其他服务使用者通过在自己的进程中调用ProcessState::self()获得一个ProcessState对象(进程级单例,单例对象定义在binder/Static.cppg Process;)(一般是使用IPCThreadState对象时间接初始化,IPCThreadState的使用非常广泛,如Looper的native层,BPBinder中,bootanimation服务,app_process中当虚拟机状态发生改变后用来关闭binder的fd等,只要是native层,几乎都会使用到这个类来进行binder的IPC通信),在构造函数中ProcessState.cpp 中open_driver()打开/dev/binder 的fd,然后通过mmap映射这个fd的BINDER_VM_SIZE 大小的到自己进程中。

之后,往往通过调用joinThreadPool(isMain = 默认true)方法和binder的驱动进行交互并初始化,让当前进程在serviciemanager处注册服务,方法内部通过mOut和mIn 这2个Parcel数据对象(提供了将数据按规定格式(如Int32,float等)进行读写的方法,各种通信状态的记录等)来向binder收发数据,首先构造mOut写入Int32 BC_ENTER_LOOPER,然后进入一个循环中,先对mIn的数据处理,然后调用talkWithDriver()(本质上是通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)与binder通信,而bwr结构是又一次对mIn和mOut的数据转换,是直接和binder驱动进行IO的数据结构,一次这样的ioctl既可以用作向binder写数据,也可以从binder读数据,是否存在读的数据需要看上下文以及外部环境是否有信息发送过来) 来和binder驱动通信),获得状态对象,然后从mIn读取cmd,然后执行executeCommand(cmd);根据cmd的类型执行回馈处理命令,将mIn的数据出,将处理好的数据放入mOut打包,等下次talkWithDriver()的时候和binder回复以及接受新命令(mIn头部的int32大小的数据存放cmd)。joinThreadPool中的这个处理binder数据的循环会运行到executeCommand() 返回 TIMED_OUT 或者ECONNREFUSED等失败退出的状态为止,退出循环,最后通过向mOut写入 (BC_EXIT_LOOPER) 并调用talkWithDriver(false) 来结束通信。

SystemServer的分析,主要流程

Main()

加载 android_servers 动态库

1. 进入 init1(args) native方法(主要启动本机服务SurfaceFlinger(屏幕),AudioFlinger,传感器等,设置通过binder监听随着servicemanager死亡的而自杀)

2. 之后调用init2()启动android服务

a) 设置进程,线程优先级

b) 检查 sys.shutdown.requested, =1重启,或关机

c) 启动一堆核心服务,并注册(如PowerManagerService,ActivityManager等)

若设置了 vold.decrypt 为 ENCRYPTING 或 ENCRYPTED(加密状态) 则设置只运行 coreApp,以此启动packageManager

。。。服务。。。。

d) 启动一些需要UI的非核心服务,并注册,大多数服务类似am,驻留在当前system_service 进程里,不像c层服务,大多数是自己独立一个进程

e) 根据当前是否为安全模式,进行不同的初始化

f) 启动其他app 进程,如devicePolicy

g) 注册am中的一个回调systemReady,在回调中 调用一堆服务的 systemReady方法

3. 循环处理binder命令(注册了自己的服务?)

 

Init1 对应源码在

/frameworks/base/services/jni/com_android_server_SystemServer.cpp

省略源码+注释若干

下面是java层的system_server的总结

java层的system_server启动了并注册和启动了很多java层服务(各个服务自己有一条线程来维持与binder通信和执行业务),进入了一个Looper循环(作用?)

System_server 中的很多服务都是在java层初始化,并驻留在system_server进程中(通过一条单独处理binder通信的线程来维持运作,如activityManager),然后注册到serviceManager

而init中也有服务的概念,这些服务中有一部分不会注册到servcieManager如ueventd,healthd ,但也有一部分会启动后以c层代码的方式注册到服务,如bootanimation

所以说关于服务有3类

1. Init中启动的native层服务,不注册到serviceManager

2. Init中启动的native层服务,会注册到serviceManager

3. System_server中启动的java层服务,会注册到serviceManager

Binder

IPCThreadState中joinThreadPool 与binder通信某些地方有点类似与TCP通信,一方发送一个Command(字符串BC_*的命令),另一方接收到并处理完后,返回一个return(字符串BR_*)状态,类似TCP的发送某SEQ帧后,接收方收到后回馈一个对应的ACK帧

一次向servicemanager添加注册服务需要经过多层

Binder驱动层,binder驱动通信层,servicemanager业务层,具体的执行注册服务的函数。4层

关键通信函数及一些常量

Binder驱动,ProcessState, ioctl()

IPCThreadState::executeCommand()

svcmgr_handler()

do_add_service()

BINDER_VERSION

BINDER_WRITE_READ---->

BINDER_THREAD_EXIT

BINDER_SET_CONTEXT_MGR

……

BR_INCREFS

BR_TRANSACTION_COMPLETE

BR_TRANSACTION----------->

BR_REPLY

……

SVC_MGR_GET_SERVICE

SVC_MGR_CHECK_SERVICE

SVC_MGR_ADD_SERVICE---->

……

svc_can_register()呼叫者uid权限校验

……

加入服务到svclist链表中

……

小结:

起点:

I##自定义INTERFACE服务类接口    : IInterface

。。。

上面画的线图,格式毁了,看截图把

浓缩:

IBinder有2个主要的子类BBinder 和 BpBinder

1.服务端继承BBinder实现transact用于在onTransact里根据cmd调用实际的接口实现的方法然后通过IPCThreadState的talkWithDriver写回结果给binder

2.客户端继承BpBinder实现transact用于根据调用的业务方法产生对应cmd和参数调用IPCThreadState::self()->transact(),然后通过waitForResponse() -> talkWithDriver() 和binder通信

3.Binder驱动和servicemanager做的工作主要是使用内存共享完成IPC,另外一个是在客户端获取服务的IBinder时,用BpBinder*的实现,而不是服务器端添加服务时给出的BBinder*。

4.当前是否服务端还是客户端?

从servicemanager通过binder通信获取到某个服务的IBinder指针后,是在interface_cast()调用的asInterface()中根据这个IBinder的queryLocalInterface() 返回IInterface* 是否为0指针来判断的

queryLocalInterface()返回是否为0指针

queryLocalInterface 是声明在IBinder中的一个虚方法,有一个默认实现(客户端中的情况)在Binder.cpp 中实现 IBinder::queryLocalInterface() (总是返回NULL)

queryLocalInterface 在服务端在BnInterface中覆盖默认的实现

服务端是调用方法IBinder->BBinder->BnInterface::queryLocalInterface(),查询用的 (用MediaPlayService举例)IMediaPlayService::descriptor == MediaPlayService::descriptor (MediaPlayService::descriptor是MediaPlayService通过继承IMediaPlayService得来,是同一个类中的成员),所以返回 this对象的指针地址,不为0

这一部分和java层的binder机制是类似的(为了方便程序员使用Binder,android提供的AIDL的主要功能就是在此层,根据自定义方法的数量生成等量的常量,用在BINDER_WRITE_READ  -> BR_TRANSACTION 与binder通信时确定远端让本方调用某个本地方法的 COMMAND 常量,然后根据command常量调用对应的方法。类似svcmgr_handler()中做的工作。)

对象转换过程:

IserviceManager <- IBinder <- BpBinder

服务使用:

IPCThreadState,ProcessState,android::Thread, android::Thread::threadLoop(), binder. 这一切是有关联的

从binder – ProcessState - android::Thread – IPCThreadState

简要流程

Binder

打开/dev/binder ,用ioctl 循环的BINDER_WRITE_READ 进行数据读写并执行对应的命令

ProcessState

主要持有/dev/binder的fd,设置与binder通信的基本参数

分析一个 开机动画的例子 bootanimation

在void SurfaceFlinger::startBootAnim()中

调用property_set("ctl.start", "bootanim"); 通过属性服务 发送控制命令 启动bootanim 服务,播放启动动画,之后当SurfaceFlinger::bootFinished()启动完成后,调用property_set("service.bootanim.exit", "1"); 设置动画退出属性为1,bootanimation会轮询检测该标志,若读取到1,则退出播放动画。

  1. 打开/dev/binder,用ioctl 检查BINDER_VERSION,设置最大线程数量 BINDER_SET_MAX_THREADS
  2. startThreadPool() 打开线程池 -> spawnPooledThread(true)

1. new 一个PoolThread 线程对象(继承android::Thread ,class Thread : virtual public RefBase, android::Thread的线程功能实际上是用pthread实现的),设置线程名称为Binder Thread 1

2. 调用PoolThread 的run方法,实际上是调用了android::Thread::run() -> androidSetCreateThreadFunc() -> pthread_create() -> Thread::_threadLoop() -> PoolThread::readyToRun() -> PoolThread::threadLoop()

mCanCallJava = isMain = true

androidCreateThreadEtc()

默认是 gCreateThreadFn = androidCreateRawThreadEtc;

有个别地方 如 AndroidRuntime.cpp 中通过  androidSetCreateThreadFunc() 将 gCreateThreadFn 指向了 javaCreateThreadEtc() ,但其实际上做了一些对JVM的额外处理后又进入了androidCreateRawThreadEtc

androidCreateRawThreadEtc 的实现分为 LINUX 下的 PTHREAD 实现 和 WIN32_THREAD 实现,这里是LINUX的实现

最关键的则是int result = pthread_create(&thread, &attr, (android_pthread_entry)entryFunction, userData);

而入口函数entryFunction 则是在 Thread::run() 中指定的Thread::_threadLoop(),此时子线程才真正跑起来

之后做了一些初始化如gettid()等,进入了一个循环,第一次进入循环则调用readyToRun()虚方法(一般由继承Thread的子类自己根据业务逻辑实现,比如BootAnimation::readyToRun()中当图形绘制的初值化工作完成后返回NO_ERROR,否则返回NO_INIT),然后android Thread框架检测,如果是 NO_ERROR 并且exitPending()未返回true,那么就调用 虚方法threadLoop();(注意,该方法不是_threadLoop()),该方法内一般让子类实现关键的业务逻辑,如BootAnimation::threadLoop()中就在进入一个死循环,播放开机动画,直到exitPending()返回true(当调用了requestExit()后exitPending会返回true,本质上是将mExitPending 变量赋值为true)后退出循环停止播放动画。

因为这里的特定子类是PoolThread所以Thread::_threadLoop()这个框架方法调用了PoolThread::readyToRun(),但PoolThread没去重写它,所以默认返回NO_ERROR,继续,调用PoolThread::threadLoop(), 调用IPCThreadState::self()->joinThreadPool(mIsMain = true); ,self()方法 主要是通过pthread_getspecific 获取保存的线程私有数据中IPCThreadState 对象的指针,如果没有获取到则新建一个IPCThreradState 对象并用pthread_key_create() 和pthread_setspecific() 对象指针存入线程私有数据集合,然后进入joinThreadPool()

IPCThreadState的executeCommand() 主要实现了和通过binder通信的一些常用命令,如获取/释放 自身服务的BBinder对象指针,增/减引用计数器,这里主要是对BR_*的反馈命令进行处理。BC_*发给binder,binder或远端服务返回一个BR_*。

Bootnimation 被 new 出来后,被第一次引用时,会触发onFirstRef()的回调,这里是bootanimation对象业务逻辑的的入口,在里面调用了run() 启动Bootnimation这个继承了Thread类的子线程,并进入threadLoop()根据当前启动阶段展示开机动画

总结:

ProcessState – PoolThread – IPCThreadState 这几个类常用在底层做binder通信使用

常见用法:

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

  1. ProcessState::self(),创建ProcessState对象,打开binder驱动,并设置基本参数
  2. ProcessState::startThreadPool(), 启动一个PoolThread子线程,调用run()让子线程初始化并进入ProcessState::threadLoop() 该方法中调用IPCThreadState::self()->joinThreadPool(mIsMain) ,让子线程在一个循环内通过talkWithDriver() 和binder、servicemanager、服务进程进行通信,并用executeCommand() 根据具体的反馈cmd执行处理命令,让这个子线程成为与binder通信的专用线程。

ProcessState::startThreadPool() =

-> new PoolThread子线程 并让它

-> Thread::run()

-> PoolThread::threadLoop()

-> IPCThreadState::self()->joinThreadPool(mIsMain) 循环的与binder通信

  1. 主线程也调用了一次 IPCThreadState::self()->joinThreadPool(); 那么主线程也进入与binder通信并执行命令的循环中

.doc文件的格式直接复制过来,有些对不上,所以截图

 

小结:

起点:

I##自定义INTERFACE服务类接口    : IInterface

|

V

在.h文件中DECLARE_META_INTERF         asBinder()

ACE(INTERFACE) 声明asInterface()

以及声明自定义的业务方法。

在.c 文件中使用

IMPLEMENT_META_INTERFACE 实现

AsInterface()方法

此处调用发起是,IPCThreadState

调用了joinThread后(PoolThread)

,在一个循环中处理binder发来

的消息,并进入executeCommand()

,其中cmd为BR_TRANSACTION

case里,会调用the_context_object

tr中的 BBinder* b->transact

法(在服务端的该方法实现是调用

onTransact,客户端的BpBinder

是直接与binder用ioctl通信)

^

|

实现BBinder::onTransact 传递给addService

根据传入参数解cmd(code)

真正实现接口(I##自定义    调用当前对象中自定义INTE

INTERFACE服务类接口)中   RFACE服务类对应的方法,拿

的方法的业务逻辑           到返回值后写入reply对象

^ß---------------------------/    ^

|                                  |

自定义INTERFACE服务类 : Bn自定义INTERFACE服务  : BnInterface   : I##自定义INTERFACE服务类接口:(IInterface)  : BBinder : IBinder  : RefBase

   Bp自定义INTERFACE服务  : BpInterface   : I##自定义INTERFACE服务类接口:(IInterface)                        : BpRefBase     --    BpBinder   :   IBinder

|                                                          |

V                                                          V

实现INTERFACE方法,但                           客户端拿到servicemanager通过binder返回过来的                          保存binder返回的IBin

是通过调用内部保存的                             IBinder后,调用asInterface转换为I##自定义                            der(BpBinder)指针

IBinder(BpBinder)                              INTERFACE服务类接口对象,直接调用想用的业务方法

的transact方法通过    《-----------------------  Bp自定义INTERFACE服务 中的实现

Binder通信(ioctl)

完成数据转发给服务

端BBinder的

onTransact处理并返回

浓缩:

IBinder有2个主要的子类BBinder 和 BpBinder

1.服务端继承BBinder实现transact用于在onTransact里根据cmd调用实际的接口实现的方法然后通过IPCThreadState的talkWithDriver写回结果给binder

2.客户端继承BpBinder实现transact用于根据调用的业务方法产生对应cmd和参数调用IPCThreadState::self()->transact(),然后通过waitForResponse() -> talkWithDriver() 和binder通信

3.Binder驱动和servicemanager做的工作主要是使用内存共享完成IPC,另外一个是在客户端获取服务的IBinder时,用BpBinder*的实现,而不是服务器端添加服务时给出的BBinder*。

4.当前是否服务端还是客户端?

从servicemanager通过binder通信获取到某个服务的IBinder指针后,是在interface_cast()调用的asInterface()中根据这个IBinder的queryLocalInterface() 返回IInterface* 是否为0指针来判断的

queryLocalInterface()返回是否为0指针

queryLocalInterface 是声明在IBinder中的一个虚方法,有一个默认实现(客户端中的情况)在Binder.cpp 中实现 IBinder::queryLocalInterface() (总是返回NULL)

queryLocalInterface 在服务端在BnInterface中覆盖默认的实现

服务端是调用方法IBinder->BBinder->BnInterface::queryLocalInterface(),查询用的 (用MediaPlayService举例)IMediaPlayService::descriptor == MediaPlayService::descriptor (MediaPlayService::descriptor是MediaPlayService通过继承IMediaPlayService得来,是同一个类中的成员),所以返回 this对象的指针地址,不为0

这一部分和java层的binder机制是类似的(为了方便程序员使用Binder,android提供的AIDL的主要功能就是在此层,根据自定义方法的数量生成等量的常量,用在BINDER_WRITE_READ  -> BR_TRANSACTION 与binder通信时确定远端让本方调用某个本地方法的 COMMAND 常量,然后根据command常量调用对应的方法。类似svcmgr_handler()中做的工作。)

对象转换过程:

IserviceManager <- IBinder <- BpBinder

服务注册:

服务使用:

IPCThreadState,ProcessState,android::Thread, android::Thread::threadLoop(), binder. 这一切是有关联的

从binder – ProcessState - android::Thread – IPCThreadState

简要流程

Binder

打开/dev/binder ,用ioctl 循环的BINDER_WRITE_READ 进行数据读写并执行对应的命令

ProcessState

主要持有/dev/binder的fd,设置与binder通信的基本参数

分析一个 开机动画的例子 bootanimation

在void SurfaceFlinger::startBootAnim()中

调用property_set("ctl.start", "bootanim"); 通过属性服务 发送控制命令 启动bootanim 服务,播放启动动画,之后当SurfaceFlinger::bootFinished()启动完成后,调用property_set("service.bootanim.exit", "1"); 设置动画退出属性为1,bootanimation会轮询检测该标志,若读取到1,则退出播放动画。

1. 打开/dev/binder,用ioctl 检查BINDER_VERSION,设置最大线程数量 BINDER_SET_MAX_THREADS

2. startThreadPool() 打开线程池 -> spawnPooledThread(true)

1. new 一个PoolThread 线程对象(继承android::Thread ,class Thread : virtual public RefBase, android::Thread的线程功能实际上是用pthread实现的),设置线程名称为Binder Thread 1

2. 调用PoolThread 的run方法,实际上是调用了android::Thread::run() -> androidSetCreateThreadFunc() -> pthread_create() -> Thread::_threadLoop() -> PoolThread::readyToRun() -> PoolThread::threadLoop()

mCanCallJava = isMain = true

androidCreateThreadEtc()

默认是 gCreateThreadFn = androidCreateRawThreadEtc;

有个别地方 如 AndroidRuntime.cpp 中通过  androidSetCreateThreadFunc() 将 gCreateThreadFn 指向了 javaCreateThreadEtc() ,但其实际上做了一些对JVM的额外处理后又进入了androidCreateRawThreadEtc

androidCreateRawThreadEtc 的实现分为 LINUX 下的 PTHREAD 实现 和 WIN32_THREAD 实现,这里是LINUX的实现

最关键的则是int result = pthread_create(&thread, &attr, (android_pthread_entry)entryFunction, userData);

而入口函数entryFunction 则是在 Thread::run() 中指定的Thread::_threadLoop(),此时子线程才真正跑起来

之后做了一些初始化如gettid()等,进入了一个循环,第一次进入循环则调用readyToRun()虚方法(一般由继承Thread的子类自己根据业务逻辑实现,比如BootAnimation::readyToRun()中当图形绘制的初值化工作完成后返回NO_ERROR,否则返回NO_INIT),然后android Thread框架检测,如果是 NO_ERROR 并且exitPending()未返回true,那么就调用 虚方法threadLoop();(注意,该方法不是_threadLoop()),该方法内一般让子类实现关键的业务逻辑,如BootAnimation::threadLoop()中就在进入一个死循环,播放开机动画,直到exitPending()返回true(当调用了requestExit()后exitPending会返回true,本质上是将mExitPending 变量赋值为true)后退出循环停止播放动画。

因为这里的特定子类是PoolThread所以Thread::_threadLoop()这个框架方法调用了PoolThread::readyToRun(),但PoolThread没去重写它,所以默认返回NO_ERROR,继续,调用PoolThread::threadLoop(), 调用IPCThreadState::self()->joinThreadPool(mIsMain = true); ,self()方法 主要是通过pthread_getspecific 获取保存的线程私有数据中IPCThreadState 对象的指针,如果没有获取到则新建一个IPCThreradState 对象并用pthread_key_create() 和pthread_setspecific() 对象指针存入线程私有数据集合,然后进入joinThreadPool()

IPCThreadState的executeCommand() 主要实现了和通过binder通信的一些常用命令,如获取/释放 自身服务的BBinder对象指针,增/减引用计数器,这里主要是对BR_*的反馈命令进行处理。BC_*发给binder,binder或远端服务返回一个BR_*。

Bootnimation 被 new 出来后,被第一次引用时,会触发onFirstRef()的回调,这里是bootanimation对象业务逻辑的的入口,在里面调用了run() 启动Bootnimation这个继承了Thread类的子线程,并进入threadLoop()根据当前启动阶段展示开机动画

总结:

ProcessState – PoolThread – IPCThreadState 这几个类常用在底层做binder通信使用

常见用法:

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

1. ProcessState::self(),创建ProcessState对象,打开binder驱动,并设置基本参数

2. ProcessState::startThreadPool(), 启动一个PoolThread子线程,调用run()让子线程初始化并进入ProcessState::threadLoop() 该方法中调用IPCThreadState::self()->joinThreadPool(mIsMain) ,让子线程在一个循环内通过talkWithDriver() 和binder、servicemanager、服务进程进行通信,并用executeCommand() 根据具体的反馈cmd执行处理命令,让这个子线程成为与binder通信的专用线程。

ProcessState::startThreadPool() =

-> new PoolThread子线程 并让它

-> Thread::run()

-> PoolThread::threadLoop()

-> IPCThreadState::self()->joinThreadPool(mIsMain) 循环的与binder通信

3. 主线程也调用了一次 IPCThreadState::self()->joinThreadPool(); 那么主线程也进入与binder通信并执行命令的循环中

Bn Bp Binder native层关系的更多相关文章

  1. Binder Native 层(二)

    Binder 框架及 Native 层 Binder机制使本地对象可以像操作当前对象一样调用远程对象,可以使不同的进程间互相通信.Binder 使用 Client/Server 架构,客户端通过服务端 ...

  2. Android Framework 分析---2消息机制Native层

    在Android的消息机制中.不仅提供了供Application 开发使用的java的消息循环.事实上java的机制终于还是靠native来实现的.在native不仅提供一套消息传递和处理的机制,还提 ...

  3. Native层和so接口和Java层

    一.Java层加载so文件 Android在Java层加载so的接口是System.loadLibrary()逐级调用的过程: System.loadLibrary()系统源码: 987    pub ...

  4. Android Java层,Native层,Lib层打印Log简介【转】

    本文转载自:https://blog.csdn.net/AndroidMage/article/details/52225068 说明: 这里我根据个人工作情况说明在各个层打印log.如有问题欢迎拍砖 ...

  5. 在Android Native层中创建Java虚拟机实例

    前言 Android应用中JNI代码,是作为本地方法运行的.而大部分情况下,这些JNI方法均需要传递Dalvik虚拟机实例作为第一个参数.例如,你需要用虚拟机实例来创建jstring和其他的Java对 ...

  6. Android Native层异步消息处理框架

     *本文系作者工作学习总结,尚有不完善及理解不恰当之处,欢迎批评指正* 一.前言 在NuPlayer中,可以发现许多类似于下面的代码: //============================== ...

  7. 在Visual Studio中使用层关系图描述系统架构、技术栈

    当需要描述项目的架构或技术栈的时候,可以考虑使用层关系图. 在解决方案下添加一个名称为"TailspinToys.DesignModel"的建模项目. 在新建的建模项目下添加一个名 ...

  8. Android逆向之旅---Native层的Hook神器Cydia Substrate使用详解

    一.前言 在之前已经介绍过了Android中一款hook神器Xposed,那个框架使用非常简单,方法也就那几个,其实最主要的是我们如何找到一个想要hook的应用的那个突破点.需要逆向分析app即可.不 ...

  9. SQLite数据库学习小结——native层实现

    1. SQlite概述 SQLite是一款轻量.快速.跨平台的嵌入式数据库,是遵守ACID(注:ACID指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity).一致性(Consi ...

随机推荐

  1. 26-限制容器对CPU的使用

    默认设置下,所有容器可以平等地使用 host CPU 资源并且没有限制. Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重.如果不指定,默认值为 1024. 与 ...

  2. [20191115]oracle实例占用内存计算.txt

    [20191115]oracle实例占用内存计算.txt --//以前学习oracle数据库时,总想了解实例占用内存多少,我曾经在一些会议底下问过一位高手,对方说计算这个相对很难,许多东西是共享的.- ...

  3. The 2017 ACM-ICPC Asia Shenyang Regional Contest

    传送门 F - Heron and His Triangle 直接打表找到规律\(f_i=4f_{i-1}+f_{i-2}\),然后大数预处理一下,对于询问直接输出就行. Code #include ...

  4. 元数据MetaData(五)

    JDBC的元数据接口有: DatabaseMetaData数据库级 ResultSetMetaData结果集级 一.DatabaseMetaData 在对数据源进行连接以后,得到一个Connectio ...

  5. 小程序-小菊花loading

    界面----交互 wx.showLoading() 显示loading提示框.需主动调用wx.hideLoading()才能关闭提示框 参数: 属性 类型 默认值 必填 说明 title string ...

  6. x86-64数据格式、通用寄存器与操作数格式

    x86-64数据格式.通用寄存器与操作数格式 数据格式 ​ Intel用术语"字(word)"表示16位数据类型,32位为"双字(double words)", ...

  7. isinstance和issubclass

    目录 一.isinstance与type 二.issubclass 一.isinstance与type 在游戏项目中,我们会在每个接口验证客户端传过来的参数类型,如果验证不通过,返回给客户端" ...

  8. 我的前端架构(jquery)汇总

    目录 我的前端架构之一--页面作用域 我的前端架构之二--统一扩展Js方法 我的前端架构之三 -- 页面规范 我的前端架构之四 -- UI控件 我的前端架构之五 -- 一些方案实现 判断对象是否是 e ...

  9. VSCode中代码在浏览器中打开及实时刷新

    实时刷新方法一: 在项目目录下运行命令: browser-sync start --server --files "**/*.css,**/*.html,**/*.js" 实施刷新 ...

  10. svn版本管理配置权限

    修改svn配置 编辑svnserve.conf文件 第19,20行删掉前面的#--意思就是打开 ancon-access = none  匿名用户不可读 auth-access = write 认证可 ...