blob: 2e13460bda052f67641e564d519569470860fb2e [file] [log] [blame]
/*
* Copyright (C) 2021 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 com.android.server.uwb;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.NonNull;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
import android.uwb.IUwbAdapter;
import android.uwb.IUwbAdapterStateCallbacks;
import android.uwb.IUwbAdfProvisionStateCallbacks;
import android.uwb.IUwbRangingCallbacks;
import android.uwb.IUwbVendorUciCallback;
import android.uwb.SessionHandle;
import android.uwb.UwbAddress;
import com.google.uwb.support.multichip.ChipInfoParams;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
/**
* Implementation of {@link android.uwb.IUwbAdapter} binder service.
*/
public class UwbServiceImpl extends IUwbAdapter.Stub {
private static final String TAG = "UwbServiceImpl";
private final Context mContext;
private final UwbInjector mUwbInjector;
private final UwbSettingsStore mUwbSettingsStore;
private final UwbServiceCore mUwbServiceCore;
UwbServiceImpl(@NonNull Context context, @NonNull UwbInjector uwbInjector) {
mContext = context;
mUwbInjector = uwbInjector;
mUwbSettingsStore = uwbInjector.getUwbSettingsStore();
mUwbServiceCore = uwbInjector.getUwbServiceCore();
registerAirplaneModeReceiver();
}
/**
* Initialize the stack after boot completed.
*/
public void initialize() {
mUwbSettingsStore.initialize();
mUwbInjector.getMultichipData().initialize();
mUwbInjector.getUwbCountryCode().initialize();
// Initialize the UCI stack at bootup.
mUwbServiceCore.setEnabled(isUwbEnabled());
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump UwbService from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
}
mUwbSettingsStore.dump(fd, pw, args);
mUwbInjector.getUwbMetrics().dump(fd, pw, args);
mUwbInjector.getUwbCountryCode().dump(fd, pw, args);
}
private void enforceUwbPrivilegedPermission() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.UWB_PRIVILEGED,
"UwbService");
}
@Override
public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
throws RemoteException {
enforceUwbPrivilegedPermission();
mUwbServiceCore.registerAdapterStateCallbacks(adapterStateCallbacks);
}
@Override
public void registerVendorExtensionCallback(IUwbVendorUciCallback callbacks)
throws RemoteException {
Log.i(TAG, "Register the callback");
enforceUwbPrivilegedPermission();
// TODO(b/210933436): Implement this.
throw new IllegalStateException("Not implemented");
/** mUwbServiceCore.registerVendorExtensionCallback(callbacks); */
}
@Override
public void unregisterVendorExtensionCallback(IUwbVendorUciCallback callbacks)
throws RemoteException {
Log.i(TAG, "Unregister the callback");
enforceUwbPrivilegedPermission();
// TODO(b/210933436): Implement this.
throw new IllegalStateException("Not implemented");
/** mUwbServiceCore.unregisterVendorExtensionCallback(callbacks); */
}
@Override
public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
throws RemoteException {
enforceUwbPrivilegedPermission();
mUwbServiceCore.unregisterAdapterStateCallbacks(adapterStateCallbacks);
}
@Override
public long getTimestampResolutionNanos(String chipId) throws RemoteException {
enforceUwbPrivilegedPermission();
checkValidChipId(chipId);
return mUwbServiceCore.getTimestampResolutionNanos();
}
@Override
public PersistableBundle getSpecificationInfo(String chipId) throws RemoteException {
enforceUwbPrivilegedPermission();
checkValidChipId(chipId);
return mUwbServiceCore.getSpecificationInfo();
}
@Override
public void openRanging(AttributionSource attributionSource,
SessionHandle sessionHandle,
IUwbRangingCallbacks rangingCallbacks,
PersistableBundle parameters,
String chipId) throws RemoteException {
enforceUwbPrivilegedPermission();
mUwbInjector.enforceUwbRangingPermissionForPreflight(attributionSource);
mUwbServiceCore.openRanging(attributionSource, sessionHandle, rangingCallbacks, parameters);
}
@Override
public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters)
throws RemoteException {
enforceUwbPrivilegedPermission();
mUwbServiceCore.startRanging(sessionHandle, parameters);
}
@Override
public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters)
throws RemoteException {
enforceUwbPrivilegedPermission();
mUwbServiceCore.reconfigureRanging(sessionHandle, parameters);
}
@Override
public void stopRanging(SessionHandle sessionHandle) throws RemoteException {
enforceUwbPrivilegedPermission();
mUwbServiceCore.stopRanging(sessionHandle);
}
@Override
public void closeRanging(SessionHandle sessionHandle) throws RemoteException {
enforceUwbPrivilegedPermission();
mUwbServiceCore.closeRanging(sessionHandle);
}
@Override
public synchronized int sendVendorUciMessage(int gid, int oid, byte[] payload)
throws RemoteException {
enforceUwbPrivilegedPermission();
// TODO(b/210933436): Implement this.
throw new IllegalStateException("Not implemented");
/**
return mUwbServiceCore.sendVendorUciMessage(rawUCi);
**/
}
@Override
public void addControlee(SessionHandle sessionHandle, PersistableBundle params) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public void removeControlee(SessionHandle sessionHandle, PersistableBundle params) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public void pause(SessionHandle sessionHandle, PersistableBundle params) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public void resume(SessionHandle sessionHandle, PersistableBundle params) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public void sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress,
PersistableBundle params, byte[] data) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public synchronized int getAdapterState() throws RemoteException {
return mUwbServiceCore.getAdapterState();
}
@Override
public synchronized void setEnabled(boolean enabled) throws RemoteException {
enforceUwbPrivilegedPermission();
persistUwbToggleState(enabled);
mUwbServiceCore.setEnabled(isUwbEnabled());
}
@Override
public List<PersistableBundle> getChipInfos() {
enforceUwbPrivilegedPermission();
List<ChipInfoParams> chipInfoParamsList = mUwbInjector.getMultichipData().getChipInfos();
List<PersistableBundle> chipInfos = new ArrayList<>();
for (ChipInfoParams chipInfoParams : chipInfoParamsList) {
chipInfos.add(chipInfoParams.toBundle());
}
return chipInfos;
}
@Override
public List<String> getChipIds() {
enforceUwbPrivilegedPermission();
List<ChipInfoParams> chipInfoParamsList = mUwbInjector.getMultichipData().getChipInfos();
List<String> chipIds = new ArrayList<>();
for (ChipInfoParams chipInfoParams : chipInfoParamsList) {
chipIds.add(chipInfoParams.getChipId());
}
return chipIds;
}
@Override
public String getDefaultChipId() {
enforceUwbPrivilegedPermission();
return mUwbInjector.getMultichipData().getDefaultChipId();
}
@Override
public PersistableBundle addServiceProfile(@NonNull PersistableBundle parameters) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public int removeServiceProfile(@NonNull PersistableBundle parameters) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public PersistableBundle getAllServiceProfiles() {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@NonNull
@Override
public PersistableBundle getAdfProvisioningAuthorities(@NonNull PersistableBundle parameters) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@NonNull
@Override
public PersistableBundle getAdfCertificateAndInfo(@NonNull PersistableBundle parameters) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public void provisionProfileAdfByScript(@NonNull PersistableBundle serviceProfileBundle,
@NonNull IUwbAdfProvisionStateCallbacks callback) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public int removeProfileAdf(@NonNull PersistableBundle serviceProfileBundle) {
enforceUwbPrivilegedPermission();
// TODO(b/200678461): Implement this.
throw new IllegalStateException("Not implemented");
}
@Override
public int handleShellCommand(@NonNull ParcelFileDescriptor in,
@NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
@NonNull String[] args) {
UwbShellCommand shellCommand = mUwbInjector.makeUwbShellCommand(this);
return shellCommand.exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
err.getFileDescriptor(), args);
}
private void persistUwbToggleState(boolean enabled) {
mUwbSettingsStore.put(UwbSettingsStore.SETTINGS_TOGGLE_STATE, enabled);
}
private boolean isUwbToggleEnabled() {
return mUwbSettingsStore.get(UwbSettingsStore.SETTINGS_TOGGLE_STATE);
}
/** Returns true if airplane mode is turned on. */
private boolean isAirplaneModeOn() {
return mUwbInjector.getSettingsInt(
Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
}
/** Returns true if UWB is enabled - based on UWB and APM toggle */
private boolean isUwbEnabled() {
return isUwbToggleEnabled() && !isAirplaneModeOn();
}
private void registerAirplaneModeReceiver() {
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleAirplaneModeEvent();
}
}, new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
}
private void handleAirplaneModeEvent() {
try {
mUwbServiceCore.setEnabled(isUwbEnabled());
} catch (Exception e) {
Log.e(TAG, "Unable to set UWB Adapter state.", e);
}
}
private void checkValidChipId(String chipId) {
if (chipId != null && !getChipIds().contains(chipId)) {
throw new IllegalArgumentException("invalid chipId: " + chipId);
}
}
}