上一篇博客《Android 6.0 如何添加完整的系统服务(app-framework-kernel)》http://www.cnblogs.com/hackfun/p/7418902.html
介绍了如何添加一个系统服务,客户端和服务端都是基于JAVA实现的OpersysService。经过进一步的学习,我将
演示如何使用C++实现一个相同功能的系统服务hfnativeservice。为了兼容OpersysService,将保留Opersys-
Service服务端中的HAL和driver,供hfnativeservice使用,即OpersysService和hfnativeservice这两个Service
都是用相同的HAL和driver。其中,hfnativeservice增加了一个服务端死亡通知机制,即hfnative-service的服
务端进程被杀掉时,客户端会收到这个通知,并做相应的清理工作。

主要围绕以下几个步骤添加一个完整的C++系统服务:
(A) 添加HAL和Driver
(B) 添加服务接口,生成动态库
(C) 添加服务端
(D) 注册服务端
(E) 添加客户端
(F) 测试

(A) 添加HAL和Driver
   这部分参考上一篇博客《Android 6.0 如何添加完整的系统服务(app-framework-kernel)》的

    (A) 添加circular-char驱动
    (B) 添加opersyshw_qemu HAL

(B) 添加服务接口,生成动态库
   
为了对外只提供服务端或客户端的接口,这里把客户端和服务端之间的通信实现细节放在一起,生成动态库so
文件,服务端和客户端在使用的时候,加载这个so就可以了。IHfNativeService.cpp对客户端和服务端提供了相同
的接口,并实现了proxy和native之间的Binder通信细节。HfNativeManager.cpp根据IHfNativeService.cpp提供的
接口,进一步封装,隐藏了客户端的是操作细节,如服务的获取,注册死亡通知等。

相关头文件:

frameworks/native/include/hfnative/HfNativeManager.h

 #ifndef ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H
#define ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H #include <stdint.h>
#include <sys/types.h> #include <binder/IBinder.h> #include <utils/RefBase.h>
#include <utils/Singleton.h>
#include <utils/threads.h>
#include <hfnative/IHfNativeService.h> namespace android {
// --------------------------------------------------------------------------- class HfNativeManager : public Singleton<HfNativeManager>
{
public:
HfNativeManager();
~HfNativeManager(); int init_hfnative(void);
void deinit_hfnative(void);
int read_queue(char *buff, int len);
int write_queue(char *buff, int len);
int test_hfnative(int value); status_t assertState();
bool checkService() const;
void resetServiceStatus(); private:
bool isDied;
// DeathRecipient interface
void hfNativeServiceDied(); mutable sp<IHfNativeService> mHfNativeServer;
mutable sp<IBinder::DeathRecipient> mDeathObserver;
}; }; // namespace android #endif // ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H

frameworks/native/include/hfnative/IHfNativeService.h

 #ifndef ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H
#define ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H #include <stdint.h>
#include <sys/types.h> #include <utils/Errors.h>
#include <utils/RefBase.h> #include <binder/IInterface.h> namespace android {
// ---------------------------------------------------------------------------- class IHfNativeService : public IInterface
{
public:
DECLARE_META_INTERFACE(HfNativeService); virtual int init_native(void) = ;
virtual void finalize_native(void) = ;
virtual int read_native(char *Buff, int Len) = ;
virtual int write_native(char *Buff, int Len) = ;
virtual int test_native(int value) = ;
}; // ---------------------------------------------------------------------------- class BnHfNativeService: public BnInterface<IHfNativeService> {
public:
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = );
}; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H

源文件:

frameworks/native/libs/hfnative/IHfNativeService.cpp

 #define LOG_TAG "HfNativeService"

 #include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <sys/types.h> #include <binder/Parcel.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <hfnative/IHfNativeService.h> namespace android { enum {
INIT_NATIVE = IBinder::FIRST_CALL_TRANSACTION,
FINALIZE_NATIVE,
READ_NATIVE,
WRITE_NATIVE,
TEST_NATIVE
}; class BpHfNativeService : public BpInterface<IHfNativeService>
{
public:
BpHfNativeService(const sp<IBinder>& impl)
: BpInterface<IHfNativeService>(impl)
{
} int init_native(void)
{
Parcel data, reply; data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
remote()->transact(INIT_NATIVE, data, &reply); return (int)reply.readInt32();
} void finalize_native(void)
{
Parcel data, reply; data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
remote()->transact(FINALIZE_NATIVE, data, &reply);
} int read_native(char *Buff, int Len)
{
Parcel data, reply; data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
data.writeInt32(Len);
remote()->transact(READ_NATIVE, data, &reply);
reply.read((void *)Buff, (size_t)Len);
return (int) reply.readInt32();
} int write_native(char *Buff, int Len)
{
Parcel data, reply; data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
data.writeInt32(Len);
data.write((const void *)Buff, (size_t)Len);
remote()->transact(WRITE_NATIVE, data, &reply);
return (int) reply.readInt32();
} int test_native(int value)
{
Parcel data, reply; data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
data.writeInt32(value);
remote()->transact(TEST_NATIVE, data, &reply);
return (int) reply.readInt32();
}
}; IMPLEMENT_META_INTERFACE(HfNativeService, "android.hfnative.HfNativeService"); status_t BnHfNativeService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
char *buff;
int len, retval;
status_t status; switch(code) {
case INIT_NATIVE:
CHECK_INTERFACE(IHfNativeService, data, reply);
retval = init_native();
reply->writeInt32(retval);
return NO_ERROR; case FINALIZE_NATIVE:
CHECK_INTERFACE(IHfNativeService, data, reply);
finalize_native();
return NO_ERROR; case READ_NATIVE: {
CHECK_INTERFACE(IHfNativeService, data, reply);
len = data.readInt32();
buff = (char *)malloc(len);
retval = read_native(buff, len);
reply->write((const void *)buff, (size_t)len);
free(buff);
reply->writeInt32(retval);
return NO_ERROR;
} break; case WRITE_NATIVE: {
CHECK_INTERFACE(IHfNativeService, data, reply);
len = data.readInt32();
buff = (char *)malloc(len);
status = data.read((void *)buff, (size_t)len);
retval = write_native(buff, len);
free(buff);
reply->writeInt32(retval);
return NO_ERROR;
} break; case TEST_NATIVE:
CHECK_INTERFACE(IHfNativeService, data, reply);
retval = test_native(data.readInt32());
reply->writeInt32(retval);
return NO_ERROR; default:
return BBinder::onTransact(code, data, reply, flags);
}
} }; // namespace android

frameworks/native/libs/hfnative/HfNativeManager.cpp

 #define LOG_TAG "HfNative"

 #include <stdint.h>
#include <sys/types.h> #include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Singleton.h> #include <binder/IBinder.h>
#include <binder/IServiceManager.h> #include <hfnative/IHfNativeService.h>
#include <hfnative/HfNativeManager.h> // ----------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------- HfNativeManager::HfNativeManager() : isDied(false)
{ } HfNativeManager::~HfNativeManager()
{
} void HfNativeManager::hfNativeServiceDied()
{
isDied = true;
mHfNativeServer.clear();
} status_t HfNativeManager::assertState() {
if (mHfNativeServer == NULL) {
// try for one second
const String16 name("hfnativeservice");
for (int i= ; i< ; i++) {
status_t err = getService(name, &mHfNativeServer);
if (err == NAME_NOT_FOUND) {
usleep();
continue;
}
if (err != NO_ERROR) {
return err;
}
break;
} init_hfnative();
ALOGI("test hfnativeservice [%d]", test_hfnative()); class DeathObserver : public IBinder::DeathRecipient {
HfNativeManager& mHfNativeManager;
virtual void binderDied(const wp<IBinder>& who) {
ALOGW("hfnativeservice died [%p]", who.unsafe_get());
mHfNativeManager.hfNativeServiceDied();
}
public:
DeathObserver(HfNativeManager& mgr) : mHfNativeManager(mgr) { }
}; mDeathObserver = new DeathObserver(*const_cast<HfNativeManager *>(this));
mHfNativeServer->asBinder(mHfNativeServer)->linkToDeath(mDeathObserver);
} return NO_ERROR;
} bool HfNativeManager::checkService() const
{
return isDied? true:false;
} void HfNativeManager::resetServiceStatus()
{
isDied = false;
} int HfNativeManager::init_hfnative(void)
{
return mHfNativeServer->init_native();
} void HfNativeManager::deinit_hfnative(void)
{
mHfNativeServer->finalize_native();
} int HfNativeManager::read_queue(char *buff, int len)
{
return mHfNativeServer->read_native(buff,len);
} int HfNativeManager::write_queue(char *buff, int len)
{
return mHfNativeServer->write_native(buff,len);
} int HfNativeManager::test_hfnative(int value)
{
return mHfNativeServer->test_native(value);
}
// ----------------------------------------------------------------------------
}; // namespace android

frameworks/native/libs/hfnative/Android.mk

 LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
IHfNativeService.cpp \
HfNativeManager.cpp LOCAL_SHARED_LIBRARIES := \
libbinder \
libcutils \
libutils LOCAL_MODULE:= libhfnativemgriface #ifneq ($(filter generic%,$(TARGET_DEVICE)),)
# Emulator build
# LOCAL_CFLAGS += -DUSE_FENCE_SYNC
#endif include $(BUILD_SHARED_LIBRARY) #ifeq (,$(ONE_SHOT_MAKEFILE))
#include $(call first-makefiles-under,$(LOCAL_PATH))
#endif

(C) 添加服务端

服务端说白了就是客户端的远程调用,如,客户端调用write_native()的时候,服务端的write_native()
也会被调用。为什么客户端不能直接调用服务端的write_native(),就是因为客户端和服务端分别处于不同的
进程中,进程间的通讯必须通过Binder、socket等机制进行传递。

frameworks/native/services/hfnativeservice/HfNativeService.h

 #ifndef ANDROID_HACKFUN_NATIVE_SERVICE_H
#define ANDROID_HACKFUN_NATIVE_SERVICE_H #include <stdint.h>
#include <sys/types.h> #include <cutils/compiler.h> #include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/threads.h> #include <binder/BinderService.h> #include <hfnative/IHfNativeService.h> namespace android { // --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
class HfNativeService : public BinderService<HfNativeService>,
public BnHfNativeService
{
public:
static char const* getServiceName() {
return "hfnativeservice";
} HfNativeService(); private:
virtual int init_native(void);
virtual void finalize_native(void);
virtual int read_native(char *Buff, int Len);
virtual int write_native(char *Buff, int Len);
virtual int test_native(int value);
}; // ---------------------------------------------------------------------------
}; // namespace android #endif // ANDROID_HACKFUN_NATIVE_SERVICE_H

frameworks/native/services/hfnativeservice/HfNativeService.cpp

 #include <stdint.h>
#include <math.h>
#include <sys/types.h> #include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Singleton.h>
#include <utils/String16.h> #include <binder/BinderService.h>
#include <binder/IServiceManager.h> #include <hfnative/IHfNativeService.h> #include "HfNativeService.h" #include <utils/misc.h>
#include <hardware/hardware.h>
#include <hardware/opersyshw.h> #include <stdio.h> namespace android {
// --------------------------------------------------------------------------- opersyshw_device_t* opersyshw_dev; HfNativeService::HfNativeService()
{
} int HfNativeService::init_native(void)
{
int err;
hw_module_t* module;
opersyshw_device_t* dev = NULL; ALOGI("init_native()"); err = hw_get_module(OPERSYSHW_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == ) {
if (module->methods->open(module, "", ((hw_device_t**) &dev)) != ) {
ALOGE("Can't open opersys module!!!");
return ;
}
} else {
ALOGE("Can't get opersys module!!!");
return ;
} opersyshw_dev = dev; return ;
} void HfNativeService::finalize_native(void)
{
opersyshw_device_t* dev = opersyshw_dev; ALOGI("finalize_native()"); if (dev == NULL) {
return;
} dev->close(); free(dev);
} int HfNativeService::read_native(char *Buff, int Len)
{
opersyshw_device_t* dev = opersyshw_dev;
char* real_byte_array = Buff;
int length; ALOGI("read_native()"); if (dev == NULL) {
return ;
} length = dev->read((char*) real_byte_array, Len); ALOGI("read data from hal: %s", (char *)real_byte_array); return length;
} int HfNativeService::write_native(char *Buff, int Len)
{
opersyshw_device_t* dev = opersyshw_dev;
char* real_byte_array = Buff;
int length; ALOGI("write_native()"); if (dev == NULL) {
return ;
} length = dev->write((char*) real_byte_array, Len); ALOGI("write data to hal: %s", (char *)real_byte_array); return length;
} int HfNativeService::test_native(int value)
{
opersyshw_device_t* dev = opersyshw_dev; if (dev == NULL) {
return ;
} ALOGI("test_native()"); return dev->test(value);
} // ---------------------------------------------------------------------------
}; // namespace android

frameworks/native/services/hfnativeservice/Android.mk

 LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
HfNativeService.cpp \ LOCAL_CFLAGS:= -DLOG_TAG=\"HfNativeService\" LOCAL_C_INCLUDES += \
$(call include-path-for, libhardware)/hardware LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libhardware \
libhfnativemgriface LOCAL_MODULE:= libhfnativeservice include $(BUILD_SHARED_LIBRARY)

(D) 注册服务端
这里启动添加的的服务,使其运行于一个独立的进程中,等待客户端的请求。

frameworks/native/cmds/hfnative/main_hfnativeservice.cpp

 #include <binder/BinderService.h>
#include <HfNativeService.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h> #include <hfnative/IHfNativeService.h> using namespace android; int main(int argc, char** argv) {
#if 1
HfNativeService::publishAndJoinThreadPool(true);
// Like the SurfaceFlinger, limit the number of binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount();
#else sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); sm->addService(String16("hfnativeservice"), new HfNativeService()); ProcessState::self()->startThreadPool();
ProcessState::self()->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
ProcessState::self()->setThreadPoolMaxThreadCount();
#endif
return ;
}

frameworks/native/cmds/hfnative/Android.mk

 LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
main_hfnativeservice.cpp LOCAL_SHARED_LIBRARIES := \
libhfnativeservice \
libbinder \
libutils LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../../services/hfnativeservice LOCAL_MODULE:= hfnativeservice include $(BUILD_EXECUTABLE)

(E) 添加客户端
    用户可以根据客户端提供的接口直接使用,无需关心复杂的客户端和服务端的通信细节。使用HfNativeManager
提供的接口,就能实现远程调用。这里创建了一个独立的线程用于等待接收服务端的死亡通知。

frameworks/base/tests/Hfnative/main_hfnativeclient.cpp

 #define LOG_TAG "HfNativeClient"

 #include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <unistd.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h> #include <hfnative/HfNativeManager.h> using namespace android; class HfThread: public Thread {
public:
HfNativeManager *hfmgr; HfThread(void *ptr) {
this->hfmgr = (HfNativeManager *)ptr;
} bool threadLoop();
}; bool HfThread::threadLoop()
{
if (hfmgr->checkService()) {
ALOGW("hfnativeservice Died, please do some clear!");
hfmgr->resetServiceStatus();
} usleep(); return true;
} int main(int argc, char **argv)
{
const char *str = {"Hello, Android !\0"};
char buff[strlen(str)]; HfNativeManager *hfmgr = new HfNativeManager(); if (hfmgr->assertState() == NO_ERROR) {
hfmgr->write_queue(const_cast<char *>(str), strlen(str));
usleep();
hfmgr->read_queue(buff, sizeof(buff));
ALOGI("Service returned: %s", buff);
} sp<HfThread> th = new HfThread((void *)hfmgr);
th->run(); ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool(); return ;
}

frameworks/base/tests/Hfnative/Android.mk

 LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
main_hfnativeclient.cpp LOCAL_SHARED_LIBRARIES := \
libhfnativemgriface \
libbinder \
libutils \
libcutils LOCAL_C_INCLUDES := \
$(ANDROID_SOURCE)/frameworks/native/include/ LOCAL_MODULE:= hfnativeclient include $(BUILD_EXECUTABLE)

(F) 测试

编译后生成对应文件:

out/target/product/<device>/.../system/lib/libhfnativemgriface.so
out/target/product/<device>/.../system/lib/libhfnativeservice.so
out/target/product/<device>/.../system/bin/hfnativeservice
out/target/product/<device>/.../system/bin/hfnativeclient

然后push到机器的相应目录
    在机器根目录下,执行以下命令,并观察对应的输出打印(注意要先启动服务端进程):

# cd system/bin
# hfnativeservice &
# service check hfnativeservice
Service hfnativeservice: found
# hfnativeclient &
# kill - pid

对应的输出打印:

......
- ::55.148 I HfNativeService: init_native() - ::55.149 D opersyshw_qemu: OPERSYS HW has been initialized - ::55.150 I HfNativeService: test_native() - ::55.151 I HfNative: test hfnativeservice [] - ::55.151 I HfNativeService: write_native() - ::55.151 D opersyshw_qemu: OPERSYS HW - write()for bytes called - ::55.151 D opersyshw_qemu: write data to driver: Hello, Android ! - ::55.151 I HfNativeService: write data to hal: Hello, Android ! - ::55.252 I HfNativeService: read_native() - ::55.252 D opersyshw_qemu: OPERSYS HW - read()for bytes called - ::55.252 D opersyshw_qemu: read data from driver: Hello, Android ! - ::55.252 I HfNativeService: read data from hal: Hello, Android ! - ::55.252 I HfNativeClient: Service returned: Hello, Android !
......
- ::08.210 W HfNative: hfnativeservice died [0xb6cc90c0] - ::08.210 I ServiceManager: service 'hfnativeservice' died - ::08.269 W HfNativeClient: hfnativeservice Died, please do some clear!
......

Android 6.0一个完整的native service的更多相关文章

  1. 【Android】 分享一个完整的项目,适合新手!

    写这个app之前是因为看了头条的一篇文章:http://www.managershare.com/post/155110,然后心想要不做一个这样的app,让手机计算就行了.也就没多想就去开始整了.   ...

  2. 我的Android进阶之旅------>如何解决Android 5.0中出现的警告: Service Intent must be explicit:

    我的Android进阶之旅-->如何解决Android 5.0中出现的警告: java.lang.IllegalArgumentException: Service Intent must be ...

  3. 我的Android进阶之旅------&gt;怎样解决Android 5.0中出现的警告: Service Intent must be explicit:

    我的Android进阶之旅-->怎样解决Android 5.0中出现的警告: java.lang.IllegalArgumentException: Service Intent must be ...

  4. Android 6.0 如何添加完整的系统服务(app-framework-kernel)

    最近学习了如何在Android 6.0上添加一个系统服务,APP如何通过新增的系统服务访问底层驱动.在这学习过程中,收获颇多,并结合学习了<Embeded Android>--Karim ...

  5. 从零開始怎么写android native service?

    从零開始怎么写android native service Android service对于从事android开发的人都不是一个陌生的东西,非常多人可能会认为服务非常easy. 服务是简单,由于复杂 ...

  6. 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发

    掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...

  7. 搭建一个完整的Android工程(一)Dagger2

    写在前面 现在越来越多的使用到了开源项目,但是仅限于使用,却不了解,更谈不上深入.也是因为越来越多的开源项目,平时工作中遇到问题也是第一时间寻找对应的开源项目,少了许多独立的思考.现在虽然能很轻松的完 ...

  8. Kubernetes — 从0到1:搭建一个完整的Kubernetes集群

    准备工作 首先,准备机器.最直接的办法,自然是到公有云上申请几个虚拟机.当然,如果条件允许的话,拿几台本地的物理服务器来组集群是最好不过了.这些机器只要满足如下几个条件即可: 满足安装 Docker ...

  9. Android(4.0.3+): Service, AsyncTask, 定时任务和UI通信

    Service使用AlarmManager实现后台定时任务 在Android 4.0.3版本中, 使用AlarmManager实现后台定时任务是比较好的方案, 其实现机制, 是利用Service的 o ...

随机推荐

  1. iOS攻城狮修炼之路

    自己总结的学习iOS的笔记,打造一个全面的知识体系,iOS攻城狮修炼之路[持续更新中] iOS学习笔记01-APP相关 iOS学习笔记02-UIScrollView iOS学习笔记03-UITable ...

  2. Codeforces Round #249 (Div. 2) 总结

    D.E还是很难的.....C不想多说什么... A:提意:给出每一组人的个数,以及一次车载容量,求出最少需要多少次才能载走所有的人. water: http://codeforces.com/cont ...

  3. [K/3Cloud] KSQL日期常量用法注意

    KSQL中用日期常量必须用{ts'" + dateTime.ToString("yyyy-M-d HH:mm:ss") + "'} 正确写法: INSERT I ...

  4. [USACO06JAN]牛的舞会The Cow Prom Tarjan

    题目描述 The N (2 <= N <= 10,000) cows are so excited: it's prom night! They are dressed in their ...

  5. Portal嵌入SAPUI5应用程序

    Embedding SAPUI5 Applications You can embed SAPUI5 applications directly into the SAP Fiori launchpa ...

  6. Ubuntu 16.04安装搜索拼音输入法

    Linux下唯一一款大厂出的输入法 1.下载 http://pinyin.sogou.com/linux/?r=pinyin 2.安装 sudo dpkg -i sogoupinyin_2.1.0.0 ...

  7. Mysql Innodb存储引擎 insert 死锁分析

    http://chenzhenianqing.cn/articles/1308.html

  8. Linux: 查找使用中的port

    找出所有使用中的port netstat -tulpn 输出 Active Internet connections (only servers) Proto Recv-Q Send-Q Local ...

  9. 例说linux内核与应用数据通信系列

    [版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet.文章仅供学习交流,请勿用于商业用途] 本系列通过源代码演示样例解说linux内核态与用户态数据通信的各种方式: 例说 ...

  10. plsql developer 64位版本

    plsql developer 64位版本 http://www.3322.cc/soft/15748.html