当前位置: 首页 > article >正文

【Android】VehiclePropertyAccess引起CarService崩溃

VehiclePropertyAccess引起CarService崩溃

VehiclePropertyAccess

VehiclePropertyAccess属性,用于定义车辆属性的访问权限。权限包括

  • 读:READ,只可以读取,不能写入。
VehiclePropertyAccess:READ
  • 写:WRITE,只可以写入,不能读取。
VehiclePropertyAccess:WRITE
  • 读写
VehiclePropertyAccess:READ_WRITE

这些车辆属性被定义在Vechile的types.hal中。编译时,会被转成VehiclPropConfig,记录到每个车辆属性中。
对于车辆属性的操作,在Android11版本,调用CarService注册监听属性,如果违反了其权限规定,会导致CarService崩溃。

原生CarService因为属性注册崩溃

违反VehiclePropertyAccess权限,导致的CarService崩溃
请添加图片描述
某应用调用 CarPropertyManager的registerCallback接口,注册监听属性ID。该操作,导致CarService反复崩溃

崩溃代码流程分析
  • CarPropertyService.java,应用调用registerListener注册监听属性ID
 @Override
 public void registerListener(int propertyId, float updateRateHz,
 ICarPropertyEventListener iCarPropertyEventListener) throws IllegalArgumentException
 {
 }
  • CarPropertyService.java,服务端对应registerListener的实现
@Override
public void registerListener(int propId, float rate, ICarPropertyEventListener listener)
{
	if (DBG) {
		Slog.d(TAG, "registerListener: propId=0x" + toHexString(propId) + " rate=" + rate);
	}
	if (listener == null) {
	 	Slog.e(TAG, "registerListener: Listener is null.");
	 	throw new IllegalArgumentException("listener cannot be null.");
	}

	IBinder listenerBinder = listener.asBinder();
	CarPropertyConfig propertyConfig;
	Client finalClient;
	synchronized (mLock) {
	propertyConfig = mConfigs.get(propId);
	if (propertyConfig == null) {
		// Do not attempt to register an invalid propId
		Slog.e(TAG, "registerListener:  propId is not in config list: 0x" + toHexString(propId));
	return;
	}
        ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
	// Get or create the client for this listener
	Client client = mClientMap.get(listenerBinder);
	if (client == null) {
		client = new Client(listener);
	}
	client.addProperty(propId, rate);
	// Insert the client into the propId --> clients map
	List<Client> clients = mPropIdClientMap.get(propId);
	if (clients == null) {
		clients = new CopyOnWriteArrayList<Client>();
		mPropIdClientMap.put(propId, clients);
	}
	if (!clients.contains(client)) {
		clients.add(client);
	}
	// Set the HAL listener if necessary
	if (!mListenerIsSet) {
		mHal.setListener(this);
	}
	// Set the new rate
	if (rate > mHal.getSampleRate(propId)) {
		mHal.subscribeProperty(propId, rate);
	}
		finalClient = client;
	}
	
	// propertyConfig and client are NonNull.
	mHandler.post(() ->
		getAndDispatchPropertyInitValue(propertyConfig, finalClient));
}
  • 两个主要流程:注册属性,获取属性初始值并派发
  public void subscribeProperty(HalServiceBase service, int property,
  	float samplingRateHz, int flags) throws IllegalArgumentException {
	if (DBG) {
      Slog.i(CarLog.TAG_HAL, "subscribeProperty, service:" + service
               + ", " + toCarPropertyLog(property));
	}
	VehiclePropConfig config;
 	synchronized (mLock) {
	     config = mAllProperties.get(property);
	}

   if (config == null) {
	throw new IllegalArgumentException("subscribe error: config is null for property 0x"
		+ toHexString(property));
   } else if (isPropertySubscribable(config)) {
       SubscribeOptions opts = new SubscribeOptions();
       opts.propId = property;
       opts.sampleRate = samplingRateHz;
       opts.flags = flags;
       synchronized (mLock) {
           assertServiceOwnerLocked(service, property);
           mSubscribedProperties.put(property, opts);
       }
       try {
           mHalClient.subscribe(opts);
       } catch (RemoteException e) {
			Slog.e(CarLog.TAG_HAL, "Failed to subscribe to " 
			+ toCarPropertyLog(property), e);
       }
   } else {
       Slog.e(CarLog.TAG_HAL, "Cannot subscribe to " + toCarPropertyLog(property));
   }
}
  • VehicleHal.java, isPropertySubscribable判断车辆属性是否可读,如果不可读不能注册。比如属性ID是"VehiclePropertyAccess:READ",就不能注册了。
static boolean isPropertySubscribable(VehiclePropConfig config) {
   if ((config.access & VehiclePropertyAccess.READ) == 0
                || (config.changeMode == VehiclePropertyChangeMode.STATIC)) {
            return false;
    }
	return true;
}
  • 接下来,获取属性初始值。哪怕不能注册的属性ID,也会去获取,所以导致了上面的CarService崩溃问题。CarPropertyService.java
private void getAndDispatchPropertyInitValue(CarPropertyConfig config, Client client) {        List<CarPropertyEvent> events = new LinkedList<>();
	int propId = config.getPropertyId();
	if (config.isGlobalProperty()) {
		CarPropertyValue value = mHal.getPropertySafe(propId, 0);
	if (value != null) {
		CarPropertyEvent event = new CarPropertyEvent(
		CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
		events.add(event);
	}
	} else {
		for (int areaId : config.getAreaIds()) {
			CarPropertyValue value = mHal.getPropertySafe(propId, areaId);
			if (value != null) {
				CarPropertyEvent event = new CarPropertyEvent(
				CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
				events.add(event);
			}
		}
	}
	try {
		client.getListener().onEvent(events);
	} catch (RemoteException ex) {
		// If we cannot send a record, its likely the connection snapped. Let the binder// death handle the situation.Slog.e(TAG, "onEvent calling failed: " + ex);
	}
}
  • HalClient.java,getValue,获取属性ID的值。
VehiclePropValue getValue(VehiclePropValue requestedPropValue) {
	final ObjectWrapper<VehiclePropValue> valueWrapper = new ObjectWrapper<>();
    int status = invokeRetriable(() -> {
        ValueResult res = internalGet(requestedPropValue);
        valueWrapper.object = res.propValue;
        return res.status;
    }, mWaitCapMs, mSleepMs);

    if (StatusCode.INVALID_ARG == status) {
        throw new IllegalArgumentException(getValueErrorMessage("get", requestedPropValue));
    }

    if (StatusCode.OK != status || valueWrapper.object == null) {
        // If valueWrapper.object is null and status is StatusCode.Ok, change the status to be// NOT_AVAILABLE.
        if (StatusCode.OK == status) {
            status = StatusCode.NOT_AVAILABLE;
        }
        Log.e(TAG, getPropertyErrorMessage("get", requestedPropValue, status));
        throw new ServiceSpecificException(status,
                "Failed to get property: 0x" + Integer.toHexString(requestedPropValue.prop)
                        + " in areaId: 0x" + Integer.toHexString(requestedPropValue.areaId));
    }

    return valueWrapper.object;
}
  • 如果是VehiclePropertyAccess:READ的属性,上述代码会抛出ServiceSpecificException异常。导致CarService崩溃。code 4,ACCESS_DENIED。

Android12修复方式

android12已修复该问题。使用了getPropertySafe,捕获异常。

/**
 * Return property or null if property is not ready yet or there is an exception in HAL.
 */
@Nullable
public CarPropertyValue getPropertySafe(int mgrPropId, int areaId) {        
try {
        return getProperty(mgrPropId, areaId);
    } catch (Exception e) {
        Slog.e(TAG, "get property value failed for property id: 0x "
                + toHexString(mgrPropId) + " area id: 0x" + toHexString(areaId)
                + " exception: " + e);
        return null;
    }
}

http://www.kler.cn/a/599475.html

相关文章:

  • 网络故障排查
  • spring和maven
  • 18,C++——哈希
  • 第3章 Internet主机与网络枚举(网络安全评估)
  • Log4j2 的核心实现和源码分析
  • day 6 中断
  • 求二叉搜索树中的众数的三种方法
  • [Android] NFC卡模拟 9.05 模拟NFC门禁卡 电梯卡等 手机代替卡片
  • <项目> 高并发服务器的HTTP协议支持
  • QML指示控件:ScrollBar与ScrollIndicator
  • 复杂任务需要多agent协同处理,对其进行逻辑编排和参数调用
  • 鸿蒙特效教程10-卡片展开/收起效果
  • 数据结构篇:空间复杂度和时间复杂度
  • netplan是如何操控NetworkManager的? 笔记250324
  • 车载以太网网络测试 -23【TCPUDP通信示例】
  • 蓝桥杯——嵌入式学习日记
  • 借助AI Agent实现数据分析
  • Python虚拟环境:从入门到实战指南
  • 在 ASP.NET Core 中实现限流(Rate Limiting):保护服务免受滥用与攻击
  • ABB机器人更换机器人本体编码器电池的具体步骤