AIDL,Android Interface Definition Language,基于安卓平台的接口定义语言。
在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
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系统中运行的相关内容还需要进一步摸索和完善。