Android CarService源码分析

news2024/12/24 8:45:19

文章目录

  • 一、CarService的基本架构
    • 1.1、Android Automative整体框架
    • 1.2、Framework CarService
    • 1.3、目录结构
      • 1.3.1、CarService
      • 1.3.2、Car APP
  • 二、CarService的启动流程
    • 2.1、系统启动后在SystemServer进程中启动CarServiceHelperService
    • 2.2、CarService启动
  • 三、CarService源码分析
    • 3.1、CarService框架源码分析
    • 3.2、CarAudioService源码分析
      • 3.2.1、构造函数
      • 3.2.2、setupDynamicRouting
      • 3.2.3、AudioManager::registerAudioPolicy
      • 3.2.4、AudioService::registerAudioPolicy
        • 3.2.4.1、流程图
        • 3.2.4.2、AudioService::registerAudioPolicy代码
        • 3.2.4.3、AudioPolicyProxy构造函数
        • 3.2.4.4、AudioPolicyProxy::setExtVolumeController
      • 3.2.5、CarAudioService::setupVolumeGroups
        • 3.2.5.1、这里通过CarVolumeGroupsHelper类加载car_volume_groups.xml文件
        • 3.2.5.2、packages/services/Car/service/res/xml/car_volume_groups.xml文件
        • 3.2.5.3、USAGE、ContextNumber和volumeGroups的关系


  团队博客: 汽车电子社区


一、CarService的基本架构

1.1、Android Automative整体框架

在这里插入图片描述
  从这幅图中我们可以看出,Android Automative是在原先Android的系统架构上增加了一些与车相关的(图中虚线框中绿色背景的)模块。
    1. Car App:包括OEM和第三方开发的App
    2. Car API:内有包含 CarSensorManager 在内的 API。位于 /platform/packages/services/Car/car-lib。
    3. CarService:系统中与车相关的服务,位于 /platform/packages/services/Car/目录。
    4. 车载 HAL:用于定义 OEM 可以实现的车辆属性的接口。包含属性元数据(例如,车辆属性是否为 int 以及允许使用哪些更改模式)。位于 hardware/libhardware/include/hardware/vehicle.h。如需了解基本参考实现,请参阅 hardware/libhardware/modules/vehicle/。

1.2、Framework CarService

  Android O/P为Automotive场景提供了一系列的服务,这些服务统被称为CarService。它们与HAL层的VehicleHAL通信,进而通过车载总线(例如CAN总线)与车身进行通讯,同时它们还为应用层的APP提供接口,从而让APP能够实现对车身的控制与状态的显示。
在这里插入图片描述   CarManage位于packages/services/Car/car-lib/src/android/car/hardware目录,
  Car
Service位于packages/services/Car/service/src/com/android/car目录。

1.3、目录结构

1.3.1、CarService

├── Android.mk
├── apicheck.mk
├── apicheck_msg_current.txt
├── apicheck_msg_last.txt
├── car-cluster-logging-renderer    //LoggingClusterRenderingService继承InstrumentClusterRenderingService
├── car-default-input-service       //按键消息处理
├── car-lib                         //提供给汽车App特有的接口,许多定制的模块都在这里实现,包括Sensor,HVAC,Cabin,ActiveParkingAssiance,Diagnostic,Vendor等
├── car-maps-placeholder            //地图软件相关
├── car_product                     //系统编译相关
├── car-support-lib                 //android.support.car
├── car-systemtest-lib              //系统测试相关
├── car-usb-handler                 //开机自启,用于管理车机USB
├── CleanSpec.mk
├── evs  
├── obd2-lib
├── PREUPLOAD.cfg
├── procfs-inspector
├── service                         //com.android.car是一个后台运行的组件,可以长时间运行并且不需要和用户去交互的,这里即使应用被销毁,它也可以正常工作
├── tests
├── tools                           //是一系列的工具,要提到的是里面的emulator,测试需要用到的。python写的,通过adb可以连接vehicleHal的工具,用于模拟测试
├── TrustAgent
└── vehicle-hal-support-lib

1.3.2、Car APP

  Car APP的相关源码位于packages/apps/Car/目录,其中packages/services/Car/car_product/build/car.mk里面决定了需要编译哪些相关apk(system/priv-app)。
  packages/services/Car/car_product/build/car.mk内容如下:

# Common make file for all car builds

PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/public
PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/private

PRODUCT_PACKAGES += \
    Bluetooth \
    CarActivityResolver \
    CarDeveloperOptions \
    CarSettingsIntelligence \
    CarManagedProvisioning \
    OneTimeInitializer \
    CarProvision \
    StatementService \
    SystemUpdater


PRODUCT_PACKAGES += \
    clatd \
    pppd \
    screenrecord

# This is for testing
ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
PRODUCT_PACKAGES += \
    DefaultStorageMonitoringCompanionApp \
    EmbeddedKitchenSinkApp \
    GarageModeTestApp \
    ExperimentalCarService \
    BugReportApp \
    NetworkPreferenceApp \
    SampleCustomInputService \
    AdasLocationTestApp \
    curl \

# SEPolicy for test apps / services
BOARD_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/test
endif

# ClusterOsDouble is the testing app to test Cluster2 framework and it can handle Cluster VHAL
# and do some Cluster OS role.
ifeq ($(ENABLE_CLUSTER_OS_DOUBLE), true)
PRODUCT_PACKAGES += ClusterHomeSample ClusterOsDouble
else
# DirectRenderingCluster is the sample app for the old Cluster framework.
PRODUCT_PACKAGES += DirectRenderingCluster
endif  # ENABLE_CLUSTER_OS_DOUBLE

PRODUCT_COPY_FILES += \
    frameworks/av/media/libeffects/data/audio_effects.conf:system/etc/audio_effects.conf

PRODUCT_PROPERTY_OVERRIDES += \
    persist.bluetooth.enablenewavrcp=false \
    ro.carrier=unknown

PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
    config.disable_systemtextclassifier=true

###
### Suggested values for multi-user properties - can be overridden
###

# Enable headless system user mode
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
    ro.fw.mu.headless_system_user?=true

# Enable user pre-creation
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
    android.car.number_pre_created_users?=1 \
    android.car.number_pre_created_guests?=1

# Enable User HAL integration
# NOTE: when set to true, VHAL must also implement the user-related properties,
# otherwise CarService will ignore it
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
    android.car.user_hal_enabled?=true

### end of multi-user properties ###

# Overlay for Google network and fused location providers
$(call inherit-product, device/sample/products/location_overlay.mk)
$(call inherit-product-if-exists, frameworks/webview/chromium/chromium.mk)
$(call inherit-product, packages/services/Car/car_product/build/car_base.mk)

# Overrides
PRODUCT_BRAND := generic
PRODUCT_DEVICE := generic
PRODUCT_NAME := generic_car_no_telephony

PRODUCT_IS_AUTOMOTIVE := true

PRODUCT_PROPERTY_OVERRIDES := \
    ro.config.ringtone=Girtab.ogg \
    ro.config.notification_sound=Tethys.ogg \
    ro.config.alarm_alert=Oxygen.ogg \
    $(PRODUCT_PROPERTY_OVERRIDES) \

PRODUCT_PROPERTY_OVERRIDES += \
    keyguard.no_require_sim=true

# TODO(b/205189147): Remove the following change after the proper fix is landed.
# Uses the local KeyGuard animation to resolve TaskView misalignment issue after display-on.
PRODUCT_SYSTEM_PROPERTIES += \
    persist.wm.enable_remote_keyguard_animation=0

# Automotive specific packages
PRODUCT_PACKAGES += \
    CarFrameworkPackageStubs \
    CarService \
    CarShell \
    CarDialerApp \
    CarRadioApp \
    OverviewApp \
    CarSystemUI \
    LocalMediaPlayer \
    CarMediaApp \
    CarMessengerApp \
    CarHTMLViewer \
    CarMapsPlaceholder \
    CarLatinIME \
    CarSettings \
    CarUsbHandler \
    android.car \
    car-frameworks-service \
    com.android.car.procfsinspector \
    libcar-framework-service-jni \
    ScriptExecutor \

# RROs
PRODUCT_PACKAGES += \
    CarPermissionControllerRRO \

# System Server components
# Order is important: if X depends on Y, then Y should precede X on the list.
PRODUCT_SYSTEM_SERVER_JARS += car-frameworks-service
# TODO: make the order optimal by appending 'car-frameworks-service' at the end
# after its dependency 'services'. Currently the order is violated because this
# makefile is included before AOSP makefile.
PRODUCT_BROKEN_SUBOPTIMAL_ORDER_OF_SYSTEM_SERVER_JARS := true

# Boot animation
PRODUCT_COPY_FILES += \
    packages/services/Car/car_product/bootanimations/bootanimation-832.zip:system/media/bootanimation.zip

PRODUCT_LOCALES := \
    en_US \
    af_ZA \
    am_ET \
    ar_EG ar_XB \
    as_IN \
    az_AZ \
    be_BY \
    bg_BG \
    bn_BD \
    bs_BA \
    ca_ES \
    cs_CZ \
    da_DK \
    de_DE \
    el_GR \
    en_AU en_CA en_GB en_IN en_XA \
    es_ES es_US \
    et_EE \
    eu_ES \
    fa_IR \
    fi_FI \
    fil_PH \
    fr_CA fr_FR \
    gl_ES \
    gu_IN \
    hi_IN \
    hr_HR \
    hu_HU \
    hy_AM \
    id_ID \
    is_IS \
    it_IT \
    iw_IL \
    ja_JP \
    ka_GE \
    kk_KZ \
    km_KH km_MH \
    kn_IN \
    ko_KR \
    ky_KG \
    lo_LA \
    lv_LV \
    lt_LT \
    mk_MK \
    ml_IN \
    mn_MN \
    mr_IN \
    ms_MY \
    my_MM \
    ne_NP \
    nl_NL \
    no_NO \
    or_IN \
    pa_IN \
    pl_PL \
    pt_BR pt_PT \
    ro_RO \
    ru_RU \
    si_LK \
    sk_SK \
    sl_SI \
    sq_AL \
    sr_RS \
    sv_SE \
    sw_TZ \
    ta_IN \
    te_IN \
    th_TH \
    tr_TR \
    uk_UA \
    ur_PK \
    uz_UZ \
    vi_VN \
    zh_CN zh_HK zh_TW \
    zu_ZA

PRODUCT_BOOT_JARS += \
    android.car

PRODUCT_HIDDENAPI_STUBS := \
    android.car-stubs-dex

PRODUCT_HIDDENAPI_STUBS_SYSTEM := \
    android.car-system-stubs-dex

PRODUCT_HIDDENAPI_STUBS_TEST := \
    android.car-test-stubs-dex

# Disable Prime Shader Cache in SurfaceFlinger to make it available faster
PRODUCT_PROPERTY_OVERRIDES += \
    service.sf.prime_shader_cache=0

二、CarService的启动流程

在这里插入图片描述

2.1、系统启动后在SystemServer进程中启动CarServiceHelperService

在这里插入图片描述   1. 在Android系统之后,系统首先会启动一个名为Zygote的进程,而Zygote进程又会启动SystemServer进程,这里我们先来看SystemServer的main方法。

frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer implements Dumpable {
        
    public static void main(String[] args) {
        new SystemServer().run();
    }
    private void run(){
            ...代码省略...
        // Start services.
        try {
            t.traceBegin("StartServices");
            startBootstrapServices(t);//启动引导服务
            startCoreServices(t);//启动核心服务
            startOtherServices(t);//启动其他服务
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            t.traceEnd(); // StartServices
        }
            ...代码省略...
    }
}

  main方法里启动了run方法,而在run方法中会调用了startOtherServices() 方法。

  2. startOtherServices和CarService相关的关键代码如下所示。

public final class SystemServer implements Dumpable {

    private static final String CAR_SERVICE_HELPER_SERVICE_CLASS =
            "com.android.internal.car.CarServiceHelperService";
    private PackageManager mPackageManager;

    private void startOtherServices() {
            mActivityManagerService.systemReady(() -> {
                          ...代码省略...
                    if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
                        t.traceBegin("StartCarServiceHelperService");
                        //如果有车机服务,则开启车机帮助服务
                        final SystemService cshs = mSystemServiceManager
                                .startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
                        if (cshs instanceof Dumpable) {
                            mDumper.addDumpable((Dumpable) cshs);
                        }
                        if (cshs instanceof DevicePolicySafetyChecker) {
                            dpms.setDevicePolicySafetyChecker((DevicePolicySafetyChecker) cshs);
                        }
                        t.traceEnd();
                    }
                          ...代码省略...
          }
    }
}

  3. SystemServiceManager的startService方法如下所示。

frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

public class SystemServiceManager {
        //存储了SystemServiceManager负责启动的各种服务
    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
    
    public SystemService startService(String className) {
        final Class<SystemService> serviceClass = loadClassFromLoader(className,this.getClass().getClassLoader());
        return startService(serviceClass);
    }
    
    @SuppressWarnings("unchecked")
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            final String name = serviceClass.getName();
            ...代码省略...
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            } 
            ...代码省略...
            startService(service);
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

    public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    }
}

  因为前面我们传入的参数为com.android.internal.car.CarServiceHelperService,所以这里startService方法首先会通过反射创建CarServiceHelperService对象实例,然后将其存储在类型ArrayList的mServices中,紧接着会调用CarServiceHelperService的onStart方法。
  4. CarServiceHelperService的onStart方法如下所示。

frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java

public class CarServiceHelperService extends SystemService
        implements Dumpable, DevicePolicySafetyChecker {
    
    @Override
    public void onStart() {
        EventLog.writeEvent(EventLogTags.CAR_HELPER_START);
        IntentFilter filter = new IntentFilter(Intent.ACTION_REBOOT);
        filter.addAction(Intent.ACTION_SHUTDOWN);
        mContext.registerReceiverForAllUsers(mShutdownEventReceiver, filter, null, null);
        mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
        mCarWatchdogDaemonHelper.connect();
        Intent intent = new Intent();
        intent.setPackage("com.android.car");
        intent.setAction(CAR_SERVICE_INTERFACE);
        //通过bindService绑定车机服务CarService
        if (!mContext.bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,
                mHandler, UserHandle.SYSTEM)) {
            Slogf.wtf(TAG, "cannot start car service");
        }
        loadNativeLibrary();
    }

    void loadNativeLibrary() {
        System.loadLibrary("car-framework-service-jni");
    }
}
packages/services/Car/car-lib/src/com/android/car/internal/common/CommonConstants.java

public final class CommonConstants {
    // CarService Constants
    public static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
}

  CarServiceHelperService的onStart方法首先创建一个Action为android.car.ICar,包名为com.android.car的Intent,然后通过bindService的方式启动该Intent对应的服务,而这个服务正是车机模块才有的CarService服务。

2.2、CarService启动

  1、系统关于CarService服务的声明如下所示。

packages/services/Car/service/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     package="com.android.car"
     coreApp="true"
     android:sharedUserId="android.uid.system">
    <!--...代码省略...-->       
    <application android:label="@string/app_title"
         android:directBootAware="true"
         android:allowBackup="false"
         android:persistent="true">

        <service android:name=".CarService"
             android:singleUser="true"
             android:exported="true">
            <intent-filter>
                <action android:name="android.car.ICar"/>
            </intent-filter>
        </service>
        <!--...代码省略...-->       
   </application>
</manifest>     

结合这个配置文件我们可以知道CarServiceHelperService最终所启动的,就是CarService这个服务。
  2、CarService的onCreate方法如下所示。

public class CarService extends Service {
    private ICarImpl mICarImpl;

    @Override
    public void onCreate() {
                  ...代码省略...
        mICarImpl = new ICarImpl(this,
                mVehicle,
                SystemInterface.Builder.defaultSystemInterface(this).build(),
                mVehicleInterfaceName);
        mICarImpl.init();

        linkToDeath(mVehicle, mVehicleDeathRecipient);
                //将ICarImpl存储到系统服务管理者ServiceManager中
        ServiceManager.addService("car_service", mICarImpl);
        SystemProperties.set("boot.car_service_created", "1");

        super.onCreate();

        initTiming.traceEnd(); // "CarService.onCreate"
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // keep it alive.
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mICarImpl;
    }
}

  CarService的onCreate方法会创建一个关键对象ICarImpl的实例,并将该实例赋值给mICarImpl属性变量,然后会调用该对象的init方法,之后还会将mICarImpl存储到ServiceManager中。另外结合CarService的onBind方法我们可以知道,CarServiceHelperService通过bindService方式开启CarService,CarService会返回mICarImpl对象,通过该Binder对象使二者建立双向跨进程通信。

三、CarService源码分析

3.1、CarService框架源码分析

  当服务启动之后, 首先调用其onCreate方法. CarService的onCreate方法实现如下:

 @Override
    public void onCreate() {
        Log.i(CarLog.TAG_SERVICE, "Service onCreate");
        //获取通知管理NotificationManager对象
        mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
        mVehicle = getVehicle();
 
        if (mVehicle == null) {
            throw new IllegalStateException("Vehicle HAL service is not available.");
        }
        try {
            mVehicleInterfaceName = mVehicle.interfaceDescriptor();
        } catch (RemoteException e) {
            throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
        }
 
        Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
 
        mICarImpl = new ICarImpl(this,
                mVehicle,
                SystemInterface.Builder.defaultSystemInterface(this).build(),
                mCanBusErrorNotifier,
                mVehicleInterfaceName);
        mICarImpl.init();
 
        linkToDeath(mVehicle, mVehicleDeathRecipient);
 
        ServiceManager.addService("car_service", mICarImpl);
        //设置SystemProperty属性  carService已创建
        SystemProperties.set("boot.car_service_created", "1");
        super.onCreate();
    }

  主要做了两件事情:
    1. 获取mVehicle 车辆相关的HIDL Binder远程对象。
    2. 创建了mICarImpl对象, 并将其添加到ServiceManager管理的服务列表中.
  这里的ICarImpl起着创建并管理各个服务的作用。在它的构造函数中,创建了各个服务的实例,并添加到服务列表中,源码如下:

packages/services/Car/service/src/com/android/car/ICarImpl.java

public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
        CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
    mContext = serviceContext;
    mSystemInterface = systemInterface;
    mHal = new VehicleHal(vehicle);
    mVehicleInterfaceName = vehicleInterfaceName;
    //创建各种重要的服务
    mUserManagerHelper = new CarUserManagerHelper(serviceContext);
    final Resources res = mContext.getResources();
    final int maxRunningUsers = res.getInteger(
            com.android.internal.R.integer.config_multiuserMaxRunningUsers);
    mCarUserService = new CarUserService(serviceContext, mUserManagerHelper,
            ActivityManager.getService(), maxRunningUsers);
    mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
    mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
            systemInterface, mUserManagerHelper);
    mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
    ....
    
    //将重要的服务缓存到 CarLocalServices
    CarLocalServices.addService(CarPowerManagementService.class, mCarPowerManagementService);
    CarLocalServices.addService(CarUserService.class, mCarUserService);
    CarLocalServices.addService(CarTrustedDeviceService.class, mCarTrustedDeviceService);


     // 将创建的服务对象依次添加到一个list中保存起来
     List<CarServiceBase> allServices = new ArrayList<>();
     allServices.add(mFeatureController);
     allServices.add(mCarUserService);
 
.....
}

  这些创建的服务就是上文介绍的汽车服务.。

3.2、CarAudioService源码分析

在这里插入图片描述

3.2.1、构造函数

  这里读取配置文件audioUseDynamicRouting确定是否使用动态Routing。

public CarAudioService(Context context) {
    mContext = context;
    mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
    mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
    mUseDynamicRouting = mContext.getResources().getBoolean(R.bool.audioUseDynamicRouting);
}

3.2.2、setupDynamicRouting

  当mUseDynamicRouting为true时,将调用setupDynamicRouting函数;该函数里会创建一个AudioPolicy ,并通过mAudioManager.registerAudioPolicy函数注册该AudioPolicy。

private void setupDynamicRouting() {
    final IAudioControl audioControl = getAudioControl();
    if (audioControl == null) {
        return;
    }
    AudioPolicy audioPolicy = getDynamicAudioPolicy(audioControl);
    int r = mAudioManager.registerAudioPolicy(audioPolicy);
    if (r != AudioManager.SUCCESS) {
        throw new RuntimeException("registerAudioPolicy failed " + r);
    }
    mAudioPolicy = audioPolicy;
}

3.2.3、AudioManager::registerAudioPolicy

public int registerAudioPolicy(@NonNull AudioPolicy policy) {
    if (policy == null) {
        throw new IllegalArgumentException("Illegal null AudioPolicy argument");
    }
    final IAudioService service = getService();
    try {
        String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
                policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController());
        if (regId == null) {
            return ERROR;
        } else {
            policy.setRegistration(regId);
        }
        // successful registration
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
    return SUCCESS;
}

  【1】policy.isVolumeController()
  这里mVolCb 的值就是通过setAudioPolicyVolumeCallback函数设置进来的,因此这里的 mVolCb 就是CarAudioService的mAudioPolicyVolumeCallback
  public boolean isVolumeController() { return mVolCb != null; }

public Builder setAudioPolicyVolumeCallback(@NonNull AudioPolicyVolumeCallback vc) {
    if (vc == null) {
        throw new IllegalArgumentException("Invalid null volume callback");
    }
    mVolCb = vc;
    return this;
}

  【2】这里的policy.cb()为IAudioPolicyCallback ,(这个很重要,后续将会用到)

public IAudioPolicyCallback cb() { return mPolicyCb; }
 
    private final IAudioPolicyCallback mPolicyCb = new IAudioPolicyCallback.Stub() {
 
        public void notifyAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
            sendMsg(MSG_FOCUS_GRANT, afi, requestResult);
            if (DEBUG) {
                Log.v(TAG, "notifyAudioFocusGrant: pack=" + afi.getPackageName() + " client="
                        + afi.getClientId() + "reqRes=" + requestResult);
            }
        }
 
        public void notifyAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {
            sendMsg(MSG_FOCUS_LOSS, afi, wasNotified ? 1 : 0);
            if (DEBUG) {
                Log.v(TAG, "notifyAudioFocusLoss: pack=" + afi.getPackageName() + " client="
                        + afi.getClientId() + "wasNotified=" + wasNotified);
            }
        }
 
        public void notifyAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
            sendMsg(MSG_FOCUS_REQUEST, afi, requestResult);
            if (DEBUG) {
                Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client="
                        + afi.getClientId() + " gen=" + afi.getGen());
            }
        }
 
        public void notifyAudioFocusAbandon(AudioFocusInfo afi) {
            sendMsg(MSG_FOCUS_ABANDON, afi, 0 /* ignored */);
            if (DEBUG) {
                Log.v(TAG, "notifyAudioFocusAbandon: pack=" + afi.getPackageName() + " client="
                        + afi.getClientId());
            }
        }
 
        public void notifyMixStateUpdate(String regId, int state) {
            for (AudioMix mix : mConfig.getMixes()) {
                if (mix.getRegistration().equals(regId)) {
                    mix.mMixState = state;
                    sendMsg(MSG_MIX_STATE_UPDATE, mix, 0/*ignored*/);
                    if (DEBUG) {
                        Log.v(TAG, "notifyMixStateUpdate: regId=" + regId + " state=" + state);
                    }
                }
            }
        }
 
        public void notifyVolumeAdjust(int adjustment) {
            sendMsg(MSG_VOL_ADJUST, null /* ignored */, adjustment);
            if (DEBUG) {
                Log.v(TAG, "notifyVolumeAdjust: " + adjustment);
            }
        }
    };

3.2.4、AudioService::registerAudioPolicy

3.2.4.1、流程图

在这里插入图片描述

3.2.4.2、AudioService::registerAudioPolicy代码

  AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener, isFocusPolicy, isVolumeController);
  这里实例化了AudioPolicyProxy,并将registerAudioPolicy参数作为AudioPolicyProxy构造函数的参数。如上所述,isVolumeController的值就是policy.isVolumeController(),因此为true。

 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
        boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) {
    AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);

    String regId = null;
    // error handling
    boolean hasPermissionForPolicy =
            (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
                    android.Manifest.permission.MODIFY_AUDIO_ROUTING));
    if (!hasPermissionForPolicy) {
        Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
                + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
        return null;
    }

    mDynPolicyLogger.log((new AudioEventLogger.StringEvent("registerAudioPolicy for "
            + pcb.asBinder() + " with config:" + policyConfig)).printLog(TAG));
    synchronized (mAudioPolicies) {
        try {
            if (mAudioPolicies.containsKey(pcb.asBinder())) {
                Slog.e(TAG, "Cannot re-register policy");
                return null;
            }
            AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
                    isFocusPolicy, isVolumeController);
            pcb.asBinder().linkToDeath(app, 0/*flags*/);
            regId = app.getRegistrationId();
            mAudioPolicies.put(pcb.asBinder(), app);
        } catch (RemoteException e) {
            // audio policy owner has already died!
            Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
                    " binder death", e);
            return null;
        }
    }
    return regId;
}
3.2.4.3、AudioPolicyProxy构造函数
AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
        boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) {
    super(config);
    setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
    mPolicyCallback = token;
    mHasFocusListener = hasFocusListener;
    mIsVolumeController = isVolumeController;
    if (mHasFocusListener) {
        mMediaFocusControl.addFocusFollower(mPolicyCallback);
        // can only ever be true if there is a focus listener
        if (isFocusPolicy) {
            mIsFocusPolicy = true;
            mMediaFocusControl.setFocusPolicy(mPolicyCallback);
        }
    }
    if (mIsVolumeController) {
        setExtVolumeController(mPolicyCallback);
    }
    connectMixes();
}
3.2.4.4、AudioPolicyProxy::setExtVolumeController

  这里设置mExtVolumeController 的值为类AudioPolicy中的IAudioPolicyCallback mPolicyCb。

private void setExtVolumeController(IAudioPolicyCallback apc) {
    if (!mContext.getResources().getBoolean(
            com.android.internal.R.bool.config_handleVolumeKeysInWindowManager)) {
        Log.e(TAG, "Cannot set external volume controller: device not set for volume keys" +
                " handled in PhoneWindowManager");
        return;
    }
    synchronized (mExtVolumeControllerLock) {
        if (mExtVolumeController != null && !mExtVolumeController.asBinder().pingBinder()) {
            Log.e(TAG, "Cannot set external volume controller: existing controller");
        }
        mExtVolumeController = apc;
    }
}

3.2.5、CarAudioService::setupVolumeGroups

3.2.5.1、这里通过CarVolumeGroupsHelper类加载car_volume_groups.xml文件
 
private void setupVolumeGroups() {
    Preconditions.checkArgument(mCarAudioDeviceInfos.size() > 0,
            "No bus device is configured to setup volume groups");
    final CarVolumeGroupsHelper helper = new CarVolumeGroupsHelper(
            mContext, R.xml.car_volume_groups);
    mCarVolumeGroups = helper.loadVolumeGroups();
    for (CarVolumeGroup group : mCarVolumeGroups) {
        for (int contextNumber : group.getContexts()) {
            int busNumber = mContextToBus.get(contextNumber);
            group.bind(contextNumber, busNumber, mCarAudioDeviceInfos.get(busNumber));
        }

        // Now that we have all our contexts, ensure the HAL gets our intial value
        group.setCurrentGainIndex(group.getCurrentGainIndex());

        Log.v(CarLog.TAG_AUDIO, "Processed volume group: " + group);
    }
    // Perform validation after all volume groups are processed
    if (!validateVolumeGroups()) {
        throw new RuntimeException("Invalid volume groups configuration");
    }
}
3.2.5.2、packages/services/Car/service/res/xml/car_volume_groups.xml文件
<volumeGroups xmlns:car="http://schemas.android.com/apk/res-auto">
    <group>
        <context car:context="music"/>
        <context car:context="call_ring"/>
        <context car:context="notification"/>
        <context car:context="system_sound"/>
    </group>
    <group>
        <context car:context="navigation"/>
        <context car:context="voice_command"/>
    </group>
    <group>
        <context car:context="call"/>
    </group>
    <group>
        <context car:context="alarm"/>
    </group>
</volumeGroups>
3.2.5.3、USAGE、ContextNumber和volumeGroups的关系

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1395001.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅聊雷池社区版(WAF)的tengine

雷池社区版是一个开源的免费Web应用防火墙&#xff08;WAF&#xff09;&#xff0c;专为保护Web应用免受各种网络攻击而设计。基于强大的Tengine&#xff0c;雷池社区版提供了一系列先进的安全功能&#xff0c;适用于中小企业和个人用户。 Tengine的故事始于2011年&#xff0c;…

Android-三方框架的源码

ARouter Arouter的整体思路是moduelA通过中间人ARouter把路由信息的存到仓库WareHouse&#xff1b;moduleB发起路由时&#xff0c;再通过中间人ARouter从仓库WareHouse取出路由信息&#xff0c;这要就实现了没有依赖的两者之间的跳转与通信。其中涉及Activity的跳转、服务prov…

微信原生小程序上传与识别以及监听多个checkbox事件打开pdf

1.点击上传并识别 组件样式<van-field border"{{ false }}" placeholder"请输入银行卡卡号" model:value"{{bankNo}}" label"卡号"><van-icon bindtap"handleChooseImg" slot"right-icon" name"sca…

网工内推 | 运维工程师,最高10K*15薪,思科认证优先

01 乐歌股份 招聘岗位&#xff1a;服务器运维工程师 职责描述&#xff1a; 1、负责公司云上云下所有服务器的日常运维工作&#xff0c;包括应用部署、巡检、备份、日志、监控&#xff0c;故障处理&#xff0c;性能优化等&#xff0c;保障公司相关系统稳定运行。 2、为开发、测…

【linux】粘滞位.yum

粘滞位 1.为什么我们普通用户可以删掉别人的文件&#xff08;包括root&#xff09;?合理吗&#xff1f; 2.删除一个文件和目标文件有关系吗&#xff1f; 没关系&#xff0c;和所处的目录有关系。 1.我们先以root身份创建一个目录&#xff0c;接着在这个目录下创建一个文件 2…

LLM之幻觉(二):大语言模型LLM幻觉缓减技术综述

LLM幻觉缓减技术分为两大主流&#xff0c;梯度方法和非梯度方法。梯度方法是指对基本LLM进行微调&#xff1b;而非梯度方法主要是在推理时使用Prompt工程技术。LLM幻觉缓减技术&#xff0c;如下图所示&#xff1a; LLM幻觉缓减技术值得注意的是&#xff1a; 检索增强生成&…

【开发篇】五、文章内容审核接口的内存问题优化

文章目录 1、初始实现思路&#xff1a;Async注解新开一个线程去审核2、改进思路一&#xff1a;加LinkedBlockingQueue阻塞队列3、改进思路二&#xff1a;RabbitMQ4、总结 背景&#xff1a;文章微服务中有一个文章审核接口&#xff0c;接口内又调用阿里云的内容安全接口进行文字…

【运维】WSL1如何升级到WSL2

升级WSL1到WSL2&#xff1a;简便快捷版 在这篇博客中&#xff0c;我们将研究如何通过一种更简便的方式&#xff0c;将WSL1迅速升级到WSL2&#xff0c;避免官方文档的繁冗步骤。如果你觉得官方方法太过冗长&#xff0c;那么这里提供的步骤可能更适合你。 官网的办法是&#xf…

Cloudflare cdn 基本使用

个人版免费试用&#xff0c;一个邮箱账号只能缓存一个网站cdn。 地址&#xff1a;cloudflare.com 创建站点 在网站创建站点&#xff0c;填上你的域名 点击进入网站 缓存全局配置 可清除缓存&#xff0c;设置浏览器缓存时间 我设置了always online,防止服务器经常不稳定 缓…

Git学习笔记(第1章):Git概述

Git是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的各种项目。 Git易于学习&#xff0c;占地面积小&#xff0c;性能极快。它具有廉价的本地库&#xff0c;方便的暂存区域和多个工作流分支等特性。其性能优于Subversion、CVS、Perforce 和…

Docker本地私有仓库搭建配置指导

一、说明 因内网主机需要拉取镜像进行Docker应用&#xff0c;因此需要一台带外主机作为内网私有仓库来提供内外其他docker业务主机使用。参考架构如下&#xff1a; 相关资源&#xff1a;加密、Distribution registry、Create and Configure Docker Registry、Registry部署、D…

Ivanti Connect Secure 曝两大零日漏洞,已被大规模利用

威胁情报公司Volexity发现&#xff0c;影响 Ivanti 的 Connect Secure VPN 和 Policy Secure 网络访问控制 (NAC) 设备的两个零日漏洞正在被大规模利用。自1月11日开始&#xff0c;多个威胁组织在大范围攻击中利用CVE-2023-46805身份验证绕过和CVE-2024-21887命令注入漏洞。 V…

Joern环境的安装(Windows版)

Joern环境的安装(Windows版) 网上很少有关于Windows下安装Joern的教程&#xff0c;而我最初使用也是装在Ubuntu虚拟机中&#xff0c;这样使用很占内存&#xff0c;影响体验感。在Windows下使用源码安装Joern也是非常简单的过程&#xff1a; 提前需要的本地环境&#xff1a; …

YOLOv5全网独家首发:DCNv4更快收敛、更高速度、更高性能,效果秒杀DCNv3、DCNv2等 ,助力检测实现暴力涨点

💡💡💡本文独家改进:DCNv4更快收敛、更高速度、更高性能,完美和YOLOv5结合,助力涨点 DCNv4优势:(1) 去除空间聚合中的softmax归一化,以增强其动态性和表达能力;(2) 优化存储器访问以最小化冗余操作以加速。这些改进显著加快了收敛速度,并大幅提高了处理速度,DCN…

vue:处理base64格式文件pdf、图片预览

一、需求&#xff1a;后端返回是base64数据&#xff0c;需要前端处理来展示文件。 二、实现方法&#xff1a; 解释一下这段代码的功能&#xff1a; &#xff09;preview(item) 是一个函数&#xff0c;接受一个参数 item&#xff0c;其中包含了文件的相关信息。 &#xff09;首…

SpringBoot的自定义starter和SpringBoot Starter机制,以及综合案例和通用模块-短信发送,基于AOP技术实现日志切面

目录 1.SpringBoot Starter机制 1.1.什么是SpringBoot Starter 1.2.为什么要使用SpringBoot Starter 1.3.应用场景 1.4.自动加载核心注解说明 2.综合案例 2.1.命名规范 2.2.通用模块-短信发送 2.2.1.创建配置类Properties 2.2.2.编写短信业务功能 2.2.3.创建自动配置…

基于Python+django影片数据爬取与数据分析设计与实现

目录 一、 前言介绍&#xff1a; 二 、功能设计&#xff1a; 三、功能实现&#xff1a; 系统登录实现 管理员实现 用户模块实现 四、库表设计&#xff1a; 五、关键代码&#xff1a; 六、论文参考&#xff1a; 七、其他案例&#xff1a; 八、源码获取&#xff1a; 一…

各省快递量数据, shp+excel,2001-2021年,已实现数据可视化

基本信息. 数据名称: 各省快递量数据 数据格式: shpexcel 数据时间&#xff1a;2001-2021年 数据几何类型: 面 数据坐标系: WGS84 数据来源&#xff1a;网络公开数据 数据字段&#xff1a; 序号字段名称字段说明1a_2001快递量/万件_2001年2a_2002快递量/万件_2002年3…

FairyGUI Day 1 导入FairyGUI

FairyGUI Unity3d引擎版本&#xff1a;Uinty3d 20233.2.3f1 1、从资产商店中将FairyGUI购入我的资产中&#xff0c;目前是免费的。 2、从我的资产中将FairyGUI导入到当前项目中。 3、我遇到的问题&#xff0c;我的Assets下有两个文件夹分别是Resources和Scenes&#xff0c;导…

AEB滤镜再破碎,安全焦虑「解不开」?

不久前&#xff0c;理想L7重大交通事故&#xff0c;再次引发了公众对AEB的热议。 根据理想汽车公布的事故视频显示&#xff0c;碰撞发生前3秒&#xff0c;车速在178km/h时驾驶员采取了制动措施&#xff0c;但车速大幅超出AEB&#xff08;自动紧急刹车系统&#xff09;的工作范…