Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7effa118 authored by Vinit Deshpande's avatar Vinit Deshpande Committed by Android (Google) Code Review
Browse files

Merge "Introduce RTT Manager" into lmp-dev

parents 4ad11aba 7686c061
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -368,6 +368,7 @@ LOCAL_SRC_FILES += \
	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
	wifi/java/android/net/wifi/IWifiScanner.aidl \
	wifi/java/android/net/wifi/IRttManager.aidl \
	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
+11 −2
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package android.app;

import android.net.wifi.IWifiScanner;
import android.net.wifi.WifiScanner;
import android.os.Build;

import android.service.persistentdata.IPersistentDataBlockService;
@@ -93,6 +91,10 @@ import android.net.wifi.passpoint.IWifiPasspointManager;
import android.net.wifi.passpoint.WifiPasspointManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.IWifiScanner;
import android.net.wifi.WifiScanner;
import android.net.wifi.IRttManager;
import android.net.wifi.RttManager;
import android.nfc.NfcManager;
import android.os.BatteryManager;
import android.os.Binder;
@@ -622,6 +624,13 @@ class ContextImpl extends Context {
                return new WifiScanner(ctx.getOuterContext(), service);
            }});

        registerService(WIFI_RTT_SERVICE, new ServiceFetcher() {
            public Object createService(ContextImpl ctx) {
                IBinder b = ServiceManager.getService(WIFI_RTT_SERVICE);
                IRttManager service = IRttManager.Stub.asInterface(b);
                return new RttManager(ctx.getOuterContext(), service);
            }});

        registerService(ETHERNET_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService(ETHERNET_SERVICE);
+12 −0
Original line number Diff line number Diff line
@@ -2067,6 +2067,7 @@ public abstract class Context {
            WIFI_P2P_SERVICE,
            WIFI_SCANNING_SERVICE,
            //@hide: ETHERNET_SERVICE,
            WIFI_RTT_SERVICE,
            NSD_SERVICE,
            AUDIO_SERVICE,
            MEDIA_ROUTER_SERVICE,
@@ -2461,6 +2462,17 @@ public abstract class Context {
    @SystemApi
    public static final String WIFI_SCANNING_SERVICE = "wifiscanner";

    /**
     * Use with {@link #getSystemService} to retrieve a {@link
     * android.net.wifi.RttManager} for ranging devices with wifi
     *
     * @see #getSystemService
     * @see android.net.wifi.RttManager
     * @hide
     */
    @SystemApi
    public static final String WIFI_RTT_SERVICE = "rttmanager";

    /**
     * Use with {@link #getSystemService} to retrieve a {@link
     * android.net.ethernet.EthernetManager} for handling management of
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net.wifi;

import android.os.Messenger;

/**
 * {@hide}
 */
interface IRttManager
{
    Messenger getMessenger();
}
+334 −0
Original line number Diff line number Diff line
package android.net.wifi;

import android.annotation.SystemApi;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;

import com.android.internal.util.AsyncChannel;

import java.util.concurrent.CountDownLatch;

/** @hide */
@SystemApi
public class RttManager {

    private static final boolean DBG = true;
    private static final String TAG = "RttManager";

    public static final int RTT_TYPE_UNSPECIFIED    = 0;
    public static final int RTT_TYPE_ONE_SIDED      = 1;
    public static final int RTT_TYPE_11_V           = 2;
    public static final int RTT_TYPE_11_MC          = 4;

    public static final int RTT_PEER_TYPE_UNSPECIFIED    = 0;
    public static final int RTT_PEER_TYPE_AP             = 1;
    public static final int RTT_PEER_TYPE_STA            = 2;       /* requires NAN */

    public static final int RTT_CHANNEL_WIDTH_20      = 0;
    public static final int RTT_CHANNEL_WIDTH_40      = 1;
    public static final int RTT_CHANNEL_WIDTH_80      = 2;
    public static final int RTT_CHANNEL_WIDTH_160     = 3;
    public static final int RTT_CHANNEL_WIDTH_80P80   = 4;
    public static final int RTT_CHANNEL_WIDTH_5       = 5;
    public static final int RTT_CHANNEL_WIDTH_10      = 6;
    public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1;

    public static final int RTT_STATUS_SUCCESS                  = 0;
    public static final int RTT_STATUS_FAILURE                  = 1;
    public static final int RTT_STATUS_FAIL_NO_RSP              = 2;
    public static final int RTT_STATUS_FAIL_REJECTED            = 3;
    public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET   = 4;
    public static final int RTT_STATUS_FAIL_TM_TIMEOUT          = 5;
    public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL  = 6;
    public static final int RTT_STATUS_FAIL_NO_CAPABILITY       = 7;
    public static final int RTT_STATUS_ABORTED                  = 8;

    public static final int REASON_UNSPECIFIED              = -1;
    public static final int REASON_INVALID_LISTENER         = -2;
    public static final int REASON_INVALID_REQUEST          = -3;

    public class Capabilities {
        int supportedType;
        int supportedPeerType;
    }

    public Capabilities getCapabilities() {
        return new Capabilities();
    }

    /** specifies parameters for RTT request */
    public static class RttParams {

        /** type of device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA */
        public int deviceType;

        /** type of RTT being sought; one of RTT_TYPE_ONE_SIDED
         *  RTT_TYPE_11_V or RTT_TYPE_11_MC or RTT_TYPE_UNSPECIFIED */
        public int requestType;

        /** mac address of the device being ranged */
        public String bssid;

        /** channel frequency that the device is on; optional */
        public int frequency;

        /** optional channel width. wider channels result in better accuracy,
         *  but they take longer time, and even get aborted may times; use
         *  RTT_CHANNEL_WIDTH_UNSPECIFIED if not specifying */
        public int channelWidth;

        /** number of samples to be taken */
        public int num_samples;

        /** number of retries if a sample fails */
        public int num_retries;
    }

    /** specifies RTT results */
    public static class RttResult {
        /** mac address of the device being ranged */
        public String bssid;

        /** status of the request */
        public int status;

        /** timestamp of completion, in microsecond since boot */
        public long ts;

        /** average RSSI observed */
        public int rssi;

        /** RSSI spread (i.e. max - min) */
        public int rssi_spread;

        /** average transmit rate */
        public int tx_rate;

        /** average round trip time in nano second */
        public long rtt_ns;

        /** standard deviation observed in round trip time */
        public long rtt_sd_ns;

        /** spread (i.e. max - min) round trip time */
        public long rtt_spread_ns;

        /** average distance in centimeter, computed based on rtt_ns */
        public long distance_cm;

        /** standard deviation observed in distance */
        public long distance_sd_cm;

        /** spread (i.e. max - min) distance */
        public long distance_spread_cm;
    }

    public static interface RttListener {
        public void onSuccess(RttResult results[]);
        public void onFailure(int reason, String description);
        public void onAborted();
    }

    public void startRanging(RttParams params[], RttListener listener) {
        validateChannel();
        sAsyncChannel.sendMessage(CMD_OP_START_RANGING, 0, removeListener(listener), params);
    }

    public void stopRanging(RttListener listener) {
        validateChannel();
        sAsyncChannel.sendMessage(CMD_OP_STOP_RANGING, 0, removeListener(listener));
    }

    /* private methods */
    public static final int CMD_OP_START_RANGING        = 0;
    public static final int CMD_OP_STOP_RANGING         = 1;
    public static final int CMD_OP_FAILED               = 2;
    public static final int CMD_OP_SUCCEEDED            = 3;
    public static final int CMD_OP_ABORTED              = 4;

    private Context mContext;
    private IRttManager mService;

    private static final int INVALID_KEY = 0;
    private static int sListenerKey = 1;

    private static final SparseArray sListenerMap = new SparseArray();
    private static final Object sListenerMapLock = new Object();

    private static AsyncChannel sAsyncChannel;
    private static CountDownLatch sConnected;

    private static final Object sThreadRefLock = new Object();
    private static int sThreadRefCount;
    private static HandlerThread sHandlerThread;

    /**
     * Create a new WifiScanner instance.
     * Applications will almost always want to use
     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
     * @param context the application context
     * @param service the Binder interface
     * @hide
     */

    public RttManager(Context context, IRttManager service) {
        mContext = context;
        mService = service;
        init();
    }

    private void init() {
        synchronized (sThreadRefLock) {
            if (++sThreadRefCount == 1) {
                Messenger messenger = null;
                try {
                    messenger = mService.getMessenger();
                } catch (RemoteException e) {
                    /* do nothing */
                } catch (SecurityException e) {
                    /* do nothing */
                }

                if (messenger == null) {
                    sAsyncChannel = null;
                    return;
                }

                sHandlerThread = new HandlerThread("WifiScanner");
                sAsyncChannel = new AsyncChannel();
                sConnected = new CountDownLatch(1);

                sHandlerThread.start();
                Handler handler = new ServiceHandler(sHandlerThread.getLooper());
                sAsyncChannel.connect(mContext, handler, messenger);
                try {
                    sConnected.await();
                } catch (InterruptedException e) {
                    Log.e(TAG, "interrupted wait at init");
                }
            }
        }
    }

    private void validateChannel() {
        if (sAsyncChannel == null) throw new IllegalStateException(
                "No permission to access and change wifi or a bad initialization");
    }

    private static int putListener(Object listener) {
        if (listener == null) return INVALID_KEY;
        int key;
        synchronized (sListenerMapLock) {
            do {
                key = sListenerKey++;
            } while (key == INVALID_KEY);
            sListenerMap.put(key, listener);
        }
        return key;
    }

    private static Object getListener(int key) {
        if (key == INVALID_KEY) return null;
        synchronized (sListenerMapLock) {
            Object listener = sListenerMap.get(key);
            return listener;
        }
    }

    private static int getListenerKey(Object listener) {
        if (listener == null) return INVALID_KEY;
        synchronized (sListenerMapLock) {
            int index = sListenerMap.indexOfValue(listener);
            if (index == -1) {
                return INVALID_KEY;
            } else {
                return sListenerMap.keyAt(index);
            }
        }
    }

    private static Object removeListener(int key) {
        if (key == INVALID_KEY) return null;
        synchronized (sListenerMapLock) {
            Object listener = sListenerMap.get(key);
            sListenerMap.remove(key);
            return listener;
        }
    }

    private static int removeListener(Object listener) {
        int key = getListenerKey(listener);
        if (key == INVALID_KEY) return key;
        synchronized (sListenerMapLock) {
            sListenerMap.remove(key);
            return key;
        }
    }

    private static class ServiceHandler extends Handler {
        ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                        sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
                    } else {
                        Log.e(TAG, "Failed to set up channel connection");
                        // This will cause all further async API calls on the WifiManager
                        // to fail and throw an exception
                        sAsyncChannel = null;
                    }
                    sConnected.countDown();
                    return;
                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
                    return;
                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
                    Log.e(TAG, "Channel connection lost");
                    // This will cause all further async API calls on the WifiManager
                    // to fail and throw an exception
                    sAsyncChannel = null;
                    getLooper().quit();
                    return;
            }

            Object listener = getListener(msg.arg2);
            if (listener == null) {
                if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
                return;
            } else {
                if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
            }

            switch (msg.what) {
                /* ActionListeners grouped together */
                case CMD_OP_SUCCEEDED :
                    ((RttListener) listener).onSuccess((RttResult[])msg.obj);
                    break;
                case CMD_OP_FAILED :
                    ((RttListener) listener).onFailure(msg.arg1, (String)msg.obj);
                    removeListener(msg.arg2);
                    break;
                case CMD_OP_ABORTED :
                    ((RttListener) listener).onAborted();
                    removeListener(msg.arg2);
                    break;
                default:
                    if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
                    return;
            }
        }
    }

}
Loading