Bn Bp Binder native层关系
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_TRANSACTION-----------> …… |
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,则退出播放动画。
- 打开/dev/binder,用ioctl 检查BINDER_VERSION,设置最大线程数量 BINDER_SET_MAX_THREADS
- 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();
- ProcessState::self(),创建ProcessState对象,打开binder驱动,并设置基本参数
- 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通信
- 主线程也调用了一次 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
法(在服务端的该方法实现是调用
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层关系的更多相关文章
- Binder Native 层(二)
Binder 框架及 Native 层 Binder机制使本地对象可以像操作当前对象一样调用远程对象,可以使不同的进程间互相通信.Binder 使用 Client/Server 架构,客户端通过服务端 ...
- Android Framework 分析---2消息机制Native层
在Android的消息机制中.不仅提供了供Application 开发使用的java的消息循环.事实上java的机制终于还是靠native来实现的.在native不仅提供一套消息传递和处理的机制,还提 ...
- Native层和so接口和Java层
一.Java层加载so文件 Android在Java层加载so的接口是System.loadLibrary()逐级调用的过程: System.loadLibrary()系统源码: 987 pub ...
- Android Java层,Native层,Lib层打印Log简介【转】
本文转载自:https://blog.csdn.net/AndroidMage/article/details/52225068 说明: 这里我根据个人工作情况说明在各个层打印log.如有问题欢迎拍砖 ...
- 在Android Native层中创建Java虚拟机实例
前言 Android应用中JNI代码,是作为本地方法运行的.而大部分情况下,这些JNI方法均需要传递Dalvik虚拟机实例作为第一个参数.例如,你需要用虚拟机实例来创建jstring和其他的Java对 ...
- Android Native层异步消息处理框架
*本文系作者工作学习总结,尚有不完善及理解不恰当之处,欢迎批评指正* 一.前言 在NuPlayer中,可以发现许多类似于下面的代码: //============================== ...
- 在Visual Studio中使用层关系图描述系统架构、技术栈
当需要描述项目的架构或技术栈的时候,可以考虑使用层关系图. 在解决方案下添加一个名称为"TailspinToys.DesignModel"的建模项目. 在新建的建模项目下添加一个名 ...
- Android逆向之旅---Native层的Hook神器Cydia Substrate使用详解
一.前言 在之前已经介绍过了Android中一款hook神器Xposed,那个框架使用非常简单,方法也就那几个,其实最主要的是我们如何找到一个想要hook的应用的那个突破点.需要逆向分析app即可.不 ...
- SQLite数据库学习小结——native层实现
1. SQlite概述 SQLite是一款轻量.快速.跨平台的嵌入式数据库,是遵守ACID(注:ACID指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity).一致性(Consi ...
随机推荐
- 26-限制容器对CPU的使用
默认设置下,所有容器可以平等地使用 host CPU 资源并且没有限制. Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重.如果不指定,默认值为 1024. 与 ...
- [20191115]oracle实例占用内存计算.txt
[20191115]oracle实例占用内存计算.txt --//以前学习oracle数据库时,总想了解实例占用内存多少,我曾经在一些会议底下问过一位高手,对方说计算这个相对很难,许多东西是共享的.- ...
- The 2017 ACM-ICPC Asia Shenyang Regional Contest
传送门 F - Heron and His Triangle 直接打表找到规律\(f_i=4f_{i-1}+f_{i-2}\),然后大数预处理一下,对于询问直接输出就行. Code #include ...
- 元数据MetaData(五)
JDBC的元数据接口有: DatabaseMetaData数据库级 ResultSetMetaData结果集级 一.DatabaseMetaData 在对数据源进行连接以后,得到一个Connectio ...
- 小程序-小菊花loading
界面----交互 wx.showLoading() 显示loading提示框.需主动调用wx.hideLoading()才能关闭提示框 参数: 属性 类型 默认值 必填 说明 title string ...
- x86-64数据格式、通用寄存器与操作数格式
x86-64数据格式.通用寄存器与操作数格式 数据格式 Intel用术语"字(word)"表示16位数据类型,32位为"双字(double words)", ...
- isinstance和issubclass
目录 一.isinstance与type 二.issubclass 一.isinstance与type 在游戏项目中,我们会在每个接口验证客户端传过来的参数类型,如果验证不通过,返回给客户端" ...
- 我的前端架构(jquery)汇总
目录 我的前端架构之一--页面作用域 我的前端架构之二--统一扩展Js方法 我的前端架构之三 -- 页面规范 我的前端架构之四 -- UI控件 我的前端架构之五 -- 一些方案实现 判断对象是否是 e ...
- VSCode中代码在浏览器中打开及实时刷新
实时刷新方法一: 在项目目录下运行命令: browser-sync start --server --files "**/*.css,**/*.html,**/*.js" 实施刷新 ...
- svn版本管理配置权限
修改svn配置 编辑svnserve.conf文件 第19,20行删掉前面的#--意思就是打开 ancon-access = none 匿名用户不可读 auth-access = write 认证可 ...