1. 程式人生 > >怎樣從C++代碼直接訪問android framework層的WifiService

怎樣從C++代碼直接訪問android framework層的WifiService

-a namespace cpi 編譯 pla desc argc 封裝 conf

說究竟,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);
}



主要的思路非常easy:

先通過:

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



怎樣從C++代碼直接訪問android framework層的WifiService