Android UWB实现——AIDL接口

372 阅读2分钟

AIDL,Android Interface Definition Language,基于安卓平台的接口定义语言。

fig_uwb_module_arch.png

在Android的UWB框架实现中,UWB Native Stack部分使用了AIDL来实现UWB HAL AIDL接口,与UWB Vendor Stack的硬件底层进行交互。

AIDL接口相关实现在包:androidx.core.uwb.backend,进行了定义。主要包括相关接口以及接口传递的自定义对象类型:

接口类型:

  • IRangingSessionCallback.aidl
  • IUwb.aidl
  • IUwbClient.aidl

自定义对象类型:

  • RangingCapabilities.aidl
  • RangingControleeParameters.aidl
  • RangingMeasurement.aidl
  • RangingParameters.aidl
  • RangingPosition.aidl
  • UwbAddress.aidl
  • UwbComplexChannel.aidl
  • UwbDevice.aidl

注:根据AIDL的规则,相关自定义对象类型均需要实现Parcelable接口,在客户端和服务器端的module都需要一份相同的模块副本。

部分自定义对象示例:UwbComplexChannel

package androidx.core.uwb.backend;
parcelable UwbComplexChannel {
  int channel;
  int preambleIndex;
}

在内部实现的代码中,对该类型进行了定义。

package androidx.core.uwb.backend.impl.internal;

/** Complex channel used by UWB ranging. */
public class UwbComplexChannel {
    @FiraParams.UwbChannel private final int mChannel;
    @FiraParams.UwbPreambleCodeIndex private final int mPreambleIndex;
    //... 实现略
}

关于接口的实现

IUwbClient.aidl接口为例:

package androidx.core.uwb.backend;
interface IUwbClient {
  boolean isAvailable();
  androidx.core.uwb.backend.RangingCapabilities getRangingCapabilities();
  androidx.core.uwb.backend.UwbAddress getLocalAddress();
  androidx.core.uwb.backend.UwbComplexChannel getComplexChannel();
  void startRanging(in androidx.core.uwb.backend.RangingParameters parameters, in androidx.core.uwb.backend.IRangingSessionCallback callback);
  void stopRanging(in androidx.core.uwb.backend.IRangingSessionCallback callback);
  void addControlee(in androidx.core.uwb.backend.UwbAddress address);
  void addControleeWithSessionParams(in androidx.core.uwb.backend.RangingControleeParameters params);
  void removeControlee(in androidx.core.uwb.backend.UwbAddress address);
}

服务器端实现

因为AIDL方法是在服务端的Binder线程池执行,在服务器端关键要实现接口的Stub方法。 相关实现均在包:androidx.core.uwb.backend.impl中,对应文件为:UwbClient.java

package androidx.core.uwb.backend.impl;

/** Implements operations of IUwbClient. */
public abstract class UwbClient extends IUwbClient.Stub {  /** IUwbClient.Stub */

    protected final UwbServiceImpl mUwbService;
    protected final RangingDevice mDevice;

    protected UwbClient(RangingDevice device, UwbServiceImpl uwbService) {
        mDevice = device;
        mUwbService = uwbService;
    }

    @Override
    public boolean isAvailable() throws RemoteException {
        return mUwbService.isAvailable();
    }

    @Override
    public RangingCapabilities getRangingCapabilities() throws RemoteException {
        androidx.core.uwb.backend.impl.internal.RangingCapabilities cap =
                mUwbService.getRangingCapabilities();
        RangingCapabilities rangingCapabilities = new RangingCapabilities();
        rangingCapabilities.supportsAzimuthalAngle = cap.supportsAzimuthalAngle();
        rangingCapabilities.supportsDistance = cap.supportsDistance();
        rangingCapabilities.supportsElevationAngle = cap.supportsElevationAngle();
        rangingCapabilities.minRangingInterval = cap.getMinRangingInterval();
        rangingCapabilities.supportedChannels = cap.getSupportedChannels()
                .stream().mapToInt(Integer::intValue).toArray();
        rangingCapabilities.supportedNtfConfigs = cap.getSupportedNtfConfigs()
                .stream().mapToInt(Integer::intValue).toArray();
        rangingCapabilities.supportedConfigIds = cap.getSupportedConfigIds()
                .stream().mapToInt(Integer::intValue).toArray();
        return rangingCapabilities;
    }
    
    @Override
    public UwbAddress getLocalAddress() throws RemoteException {
        androidx.core.uwb.backend.impl.internal.UwbAddress address = mDevice.getLocalAddress();
        UwbAddress uwbAddress = new UwbAddress();
        uwbAddress.address = address.toBytes();
        return uwbAddress;
    }

    protected void setRangingParameters(RangingParameters parameters) throws RemoteException {
        androidx.core.uwb.backend.impl.internal.UwbComplexChannel channel =
                new androidx.core.uwb.backend.impl.internal.UwbComplexChannel(
                        parameters.complexChannel.channel, parameters.complexChannel.preambleIndex);

        List<androidx.core.uwb.backend.impl.internal.UwbAddress> addresses = new ArrayList<>();
        for (androidx.core.uwb.backend.UwbDevice device : parameters.peerDevices) {
            addresses.add(androidx.core.uwb.backend.impl.internal.UwbAddress
                    .fromBytes(device.address.address));
        }

        UwbRangeDataNtfConfig uwbRangeDataNtfConfig = new UwbRangeDataNtfConfig.Builder().build();
        mDevice.setRangingParameters(
          new androidx.core.uwb.backend.impl.internal.RangingParameters(
              parameters.uwbConfigId, parameters.sessionId, parameters.subSessionId,
              parameters.sessionKeyInfo, parameters.subSessionKeyInfo,
              channel, addresses, parameters.rangingUpdateRate, uwbRangeDataNtfConfig,
             Utils.DURATION_2_MS, Utils.AUTOMATIC, false));
    }

    protected androidx.core.uwb.backend.impl.internal.RangingSessionCallback convertCallback(
            IRangingSessionCallback callback) {
        return new RangingSessionCallback() {
        
            @Override
            public void onRangingInitialized(UwbDevice device) {
                androidx.core.uwb.backend.UwbDevice backendDevice =
                        new androidx.core.uwb.backend.UwbDevice();
                backendDevice.address = new UwbAddress();
                backendDevice.address.address = device.getAddress().toBytes();
                try {
                    callback.onRangingInitialized(backendDevice);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onRangingResult(UwbDevice device, RangingPosition position) {
                androidx.core.uwb.backend.UwbDevice backendDevice =
                        new androidx.core.uwb.backend.UwbDevice();
                backendDevice.address = new UwbAddress();
                backendDevice.address.address = device.getAddress().toBytes();
                androidx.core.uwb.backend.RangingPosition rangingPosition =
                        new androidx.core.uwb.backend.RangingPosition();
                RangingMeasurement distance = new RangingMeasurement();
                distance.confidence = position.getDistance().getConfidence();
                distance.value = position.getDistance().getValue();
                rangingPosition.distance = distance;
                if (position.getAzimuth() != null) {
                    RangingMeasurement azimuth = new RangingMeasurement();
                    azimuth.confidence = position.getAzimuth().getConfidence();
                    azimuth.value = position.getAzimuth().getValue();
                    rangingPosition.azimuth = azimuth;
                }

                if (position.getElevation() != null) {
                    RangingMeasurement elevation = new RangingMeasurement();
                    elevation.confidence = position.getElevation().getConfidence();
                    elevation.value = position.getElevation().getValue();
                    rangingPosition.elevation = elevation;
                }

                rangingPosition.elapsedRealtimeNanos = position.getElapsedRealtimeNanos();
                try {
                    callback.onRangingResult(backendDevice, rangingPosition);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onRangingSuspended(UwbDevice device, int reason) {
                androidx.core.uwb.backend.UwbDevice backendDevice =
                        new androidx.core.uwb.backend.UwbDevice();
                backendDevice.address = new UwbAddress();
                backendDevice.address.address = device.getAddress().toBytes();
                try {
                    callback.onRangingSuspended(backendDevice, reason);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        };
    }
}

可以看到,在服务端的实现上,extends IUwbClient.Stub,并将AIDL中定义的部分接口。 对于远程调用接口,若出现异常,均抛出远程异常RemoteException

客户端实现

在底层,android.hardware.uwb

图片.png

package android.hardware.uwb;
@VintfStability
interface IUwb {
  List<String> getChips();
  android.hardware.uwb.IUwbChip getChip(String name);
}
package android.hardware.uwb;
@VintfStability
interface IUwbChip {
  String getName();
  void open(in android.hardware.uwb.IUwbClientCallback clientCallback);
  void close();
  void coreInit();
  void sessionInit(int sessionId);
  int getSupportedAndroidUciVersion();
  int sendUciMessage(in byte[] data);
}
package android.hardware.uwb;
@VintfStability
interface IUwbClientCallback {
  oneway void onUciMessage(in byte[] data);
  oneway void onHalEvent(in android.hardware.uwb.UwbEvent event, in android.hardware.uwb.UwbStatus status);
}

各AIDL接口之间的关系,以及如何在Android系统中运行的相关内容还需要进一步摸索和完善。