说到底,Java层的service就是就C++层的binder的封装,所以从原理上来讲通过C++代码直接访问android framework层的service是完全可能的,这篇文章以访问WifiService为例,讲解如何去实现这个功能。
费话少说,直接上代码:
WifiTest.cpp
#include <sys/types.h> #include <unistd.h> #include <grp.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <utils/Log.h> #include <utils/String16.h> //#include <utils/Vector.h> #include <utils/List.h> #include <utils/PropertyMap.h> using namespace android; #define WIFI_SERVICE "wifi" const String16 WIFI_DESCRIPTOR("android.net.wifi.IWifiManager"); class ScanResult { private: ScanResult& operator=(const ScanResult& o); public: ScanResult(const ScanResult& o): mSsid(o.mSsid),mBssid(o.mBssid),mCaps(o.mCaps),mLevel(o.mLevel),mFrequency(o.mFrequency),mTimestamp(o.mTimestamp) { } ScanResult(String8 ssid,String16 bssid,String16 caps,int level,int freq,int64_t timeStamp): mSsid(ssid),mBssid(bssid),mCaps(caps),mLevel(level),mFrequency(freq),mTimestamp(timeStamp) { } void dump() { char temp[130]; int size; memset(temp,0,sizeof(temp)); printf("ssid %s \n",mSsid.string()); size = mBssid.size(); if(size > sizeof(temp)/2 - 1) { size = sizeof(temp)/2 - 1; } utf16_to_utf8(mBssid.string(), size, temp); printf("Bssid %s \n",temp); size = mCaps.size(); if(size > sizeof(temp)/2 - 1) { size = sizeof(temp)/2 - 1; } utf16_to_utf8(mCaps.string(), size, temp); printf("ssid %s \n",temp); printf("level %d \n",mLevel); printf("freq %d \n",mFrequency); printf("freq %ld \n",mTimestamp); } private: String8 mSsid; String16 mBssid; String16 mCaps; int mLevel; int mFrequency; int64_t mTimestamp; }; class IWifiService: public android::IInterface { public: DECLARE_META_INTERFACE(WifiService) virtual void startScan(int forceActive) = 0; virtual int getScanResults(List<ScanResult> &list) = 0; virtual bool setWifiEnabled(bool enable) = 0; }; class BpWifiService: public android::BpInterface<IWifiService> { enum { FIRST_CALL_TRANSACTION = 1, TRANSACTION_getConfiguredNetworks = (android::IBinder::FIRST_CALL_TRANSACTION + 0), TRANSACTION_addOrUpdateNetwork = (android::IBinder::FIRST_CALL_TRANSACTION + 1), TRANSACTION_removeNetwork = (android::IBinder::FIRST_CALL_TRANSACTION + 2), TRANSACTION_enableNetwork = (android::IBinder::FIRST_CALL_TRANSACTION + 3), TRANSACTION_disableNetwork = (android::IBinder::FIRST_CALL_TRANSACTION + 4), TRANSACTION_pingSupplicant = (android::IBinder::FIRST_CALL_TRANSACTION + 5), TRANSACTION_startScan = (android::IBinder::FIRST_CALL_TRANSACTION + 6), TRANSACTION_getScanResults = (android::IBinder::FIRST_CALL_TRANSACTION + 7), TRANSACTION_disconnect = (android::IBinder::FIRST_CALL_TRANSACTION + 8), TRANSACTION_reconnect = (android::IBinder::FIRST_CALL_TRANSACTION + 9), TRANSACTION_reassociate = (android::IBinder::FIRST_CALL_TRANSACTION + 10), TRANSACTION_getConnectionInfo = (android::IBinder::FIRST_CALL_TRANSACTION + 11), TRANSACTION_setWifiEnabled = (android::IBinder::FIRST_CALL_TRANSACTION + 12), TRANSACTION_getWifiEnabledState = (android::IBinder::FIRST_CALL_TRANSACTION + 13), TRANSACTION_setCountryCode = (android::IBinder::FIRST_CALL_TRANSACTION + 14), TRANSACTION_setFrequencyBand = (android::IBinder::FIRST_CALL_TRANSACTION + 15), TRANSACTION_getFrequencyBand = (android::IBinder::FIRST_CALL_TRANSACTION + 16), TRANSACTION_isDualBandSupported = (android::IBinder::FIRST_CALL_TRANSACTION + 17), TRANSACTION_saveConfiguration = (android::IBinder::FIRST_CALL_TRANSACTION + 18), TRANSACTION_getDhcpInfo = (android::IBinder::FIRST_CALL_TRANSACTION + 19), TRANSACTION_acquireWifiLock = (android::IBinder::FIRST_CALL_TRANSACTION + 20), TRANSACTION_updateWifiLockWorkSource = (android::IBinder::FIRST_CALL_TRANSACTION + 21), TRANSACTION_releaseWifiLock = (android::IBinder::FIRST_CALL_TRANSACTION + 22), TRANSACTION_initializeMulticastFiltering = (android::IBinder::FIRST_CALL_TRANSACTION + 23), TRANSACTION_isMulticastEnabled = (android::IBinder::FIRST_CALL_TRANSACTION + 24), TRANSACTION_acquireMulticastLock = (android::IBinder::FIRST_CALL_TRANSACTION + 25), TRANSACTION_releaseMulticastLock = (android::IBinder::FIRST_CALL_TRANSACTION + 26), TRANSACTION_setWifiApEnabled = (android::IBinder::FIRST_CALL_TRANSACTION + 27), TRANSACTION_getWifiApEnabledState = (android::IBinder::FIRST_CALL_TRANSACTION + 28), TRANSACTION_getWifiApConfiguration = (android::IBinder::FIRST_CALL_TRANSACTION + 29), TRANSACTION_setWifiApConfiguration = (android::IBinder::FIRST_CALL_TRANSACTION + 30), TRANSACTION_startWifi = (android::IBinder::FIRST_CALL_TRANSACTION + 31), TRANSACTION_stopWifi = (android::IBinder::FIRST_CALL_TRANSACTION + 32), TRANSACTION_addToBlacklist = (android::IBinder::FIRST_CALL_TRANSACTION + 33), TRANSACTION_clearBlacklist = (android::IBinder::FIRST_CALL_TRANSACTION + 34), TRANSACTION_getWifiServiceMessenger = (android::IBinder::FIRST_CALL_TRANSACTION + 35), TRANSACTION_getWifiStateMachineMessenger = (android::IBinder::FIRST_CALL_TRANSACTION + 36), TRANSACTION_getConfigFile = (android::IBinder::FIRST_CALL_TRANSACTION + 37), TRANSACTION_captivePortalCheckComplete = (android::IBinder::FIRST_CALL_TRANSACTION + 38), }; public: BpWifiService(const android::sp<android::IBinder>& impl): android::BpInterface<IWifiService>(impl) { } void startScan(int forceActive) { android::Parcel data, reply; data.writeInterfaceToken(WIFI_DESCRIPTOR); if (forceActive) { data.writeInt32(1); } else { data.writeInt32(0); } remote()->transact(TRANSACTION_startScan, data, &reply, 0); } virtual int getScanResults(List<ScanResult> &list) { Parcel data, reply; data.writeInterfaceToken(WIFI_DESCRIPTOR); remote()->transact(TRANSACTION_getScanResults, data, &reply, 0); if (0 != reply.readExceptionCode()) { return 0; } int count = reply.readInt32(); for (int i=0;i<count;i++) { String8 ssid; int res = reply.readInt32(); if (res != 0) { reply.readInt32(); reply.readInt32(); int length = reply.readInt32(); ssid = String8((const char*)reply.readInplace(length),length); } // utf16_to_utf8(const char16_t* src, size_t src_len, char* dst); String16 BSSID = reply.readString16(); String16 caps = reply.readString16(); int level = reply.readInt32(); int frequency = reply.readInt32(); int64_t timestamp = reply.readInt64(); ScanResult result(ssid,BSSID,caps,level,frequency,timestamp); list.push_back(result); } return count; } bool setWifiEnabled(bool enable) { Parcel data, reply; data.writeInterfaceToken(WIFI_DESCRIPTOR); if(enable) data.writeInt32(1); else data.writeInt32(0); remote()->transact(TRANSACTION_setWifiEnabled, data,&reply,0); reply.readExceptionCode(); return 0!=reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(WifiService, WIFI_DESCRIPTOR) int main(int argc, char *argv[]) { android::sp<android::IServiceManager> sm = android::defaultServiceManager(); android::sp<android::IBinder> binder; android::sp<IWifiService> wifi; binder = sm->getService(android::String16(WIFI_SERVICE)); if (binder == 0) { return 1; } wifi = android::interface_cast<IWifiService>(binder); wifi->setWifiEnabled(true); printf("+++++scan start"); wifi->startScan(1); for(int i=0;i<10;i++) { usleep(1*1000*1000); List<ScanResult> list; wifi->getScanResults(list); if(list.size() > 0) { for(List<ScanResult>::iterator it = list.begin();it != list.end();++it) { (*it).dump(); } break; } } return(0); }
基本的思路很简单:
先通过:
android::defaultServiceManager()->getService(android::String16(WIFI_SERVICE));
获取binder接口,再通过Parcel读与binder,具体的实现可以参考IWifiManager.java的代码。
编译后运行以上的代码可以得到类似以下的输出:
ssid wifitest
Bssid b8:55:10:84:13:57
ssid [WPA-PSK-CCMP][WPA2-PSK-CCMP][WPS][ESS]
level -55
freq 2447
time stamp 1073922473
ssid test
Bssid 08:bd:43:c3:a9:96
ssid [WPA2-PSK-CCMP][WPS][ESS]
level -66
freq 2462
time stamp 1073922473
完整代码下载:
http://download.csdn.net/detail/i2cbus/7613361