모바일

[AOSP] Framework Service와 HAL 바인드 과정 살펴보기

손가든 2024. 11. 26. 20:55

저번에 AOSP의 아키텍쳐를 살펴봤다.

 

오늘은 그 아키텍처중에 Android Framework 가장 아랫단에 있는 Service Layer가 Hal과 연결되어 있는 방식을 살펴보겠다.

 

시스템 서비스는 HAL과 두가지 형태로 연결되어 있는데,

 

Wifi의 시스템적 기능을 제공하는 인터페이스인 Supplicant의 HAL 과

제조사가 제작하여 하드웨어 칩의 기능을 제공하는 인터페이스인 VendorHAL이다.

 

이들은 각각 대응되는 Service 클래스에서 Binder 객체에 의해 바인드되어 요청과 응답을 통신하는 방식으로 연결되어 있다.

 

이 바인더 과정이 어떻게 되는지 살펴보겠다.


 

1. SystemServce – HAL Binder 연결 과정 (Vendor Hal)

 

Vendor Hal의 바인더 과정을 살펴보기 위해 WifiVendorHal의 서비스 메소드가

Hal 구현체를 어디서 가져와서 사용하는지를 먼저 살펴보자.

 

WifiVendorHal을 살펴보니 Map 자료구조에 이미 바인더되어 있는 Hal 인터페이스를 저장해두고 있었고,

이는 ClientModeImpl 클래스로부터 전달받은 인터페이스 명을 가지고 WifiVendorHal에서 Map 자료구조에 요청하여 해당 인터페이스를 가져오도록 설계되어 있었다.

 

그래서 인터페이스명을 제공한 ClientModeImpl 클래스에서 인터페이스명이 어디서 생성된 건지 확인하기 위해 ClientModeImpl 코드를 분석했다.

 

 

ClientModeImpl 클래스를 확인해보니 지역 변수로 인터페이스 명을 인자로 사용하고 있었다.

 

이 인터페이스명은 setOperationalMode라는 메소드를 통해 초기화 되는데,

이는 Wifi State 상속 코드에서 호출되고 있었다.

 

 

 

그래서 Wifi의 State가 무엇인지 코드 내부를 들여다보았다.

 

코드를 확인해보니 내부 State Machine이라는 클래스에서 화면에 보이는 모드 네가지를 Linked list처럼 연결해놓고,

eventListener가 등록되어 있었다.

 

그리고 Looper라는 개별 스레드를 생성해서 이벤트 리스너가 받은 상태 전환 처리를 자동으로 수행하도록 되어있어서

오른쪽 코드처럼 override 하여 해당 상태의 동작 코드를 구현하면 돌아가도록 설계되어 있었다.

 

여기서 오른쪽의 idle 상태 처리 코드를 보면 CMD_START 명령어 이벤트를 받았을 때,

, 사용자가 와이파이를 켰을 때, scanOnlyMode로 직접 전환되도록 설정하면서

ClientModeManager 클래스의 지역 변수인 인터페이스명을 초기화하고 있었는데,

 

ClientModeManager 클래스의 인터페이스명을 통해서 (아래 보이는 코드처럼) Scan mode로 진입했을 때,

ClientModeImpl 클래스의 인터페이스명을 셋업하고 있기 때문에

1번과정의 setupInterfaceforClientInScanMode 메소드에서 어떻게 인터페이스 명이 생성되어 초기화하는지 해당 코드를 확인했다.

 

 

 

내부를 들여다보니 Hal을 연결하고 Map 자료구조에 인터페이스를 매핑시켜 전달하는 로직이 들어있었다.

 

내부 흐름의 절차가 매우 많아서 주요 메소드만 자료로 가져왔다.

 

먼저 이 메소드는 Starthal 메소드를 수행하면서 바인더 연결 흐름을 시작한다.

 

이는 메소드를 타고 가면서 WifiVendorHal 클래스의 startVendorHal을 호출하게 된다.

이 과정이 1번 화살표에 표시되어 있다.

 

그리고 WifiVendorHal startVendorHal 메소드는 HalDeviceManager 클래스의 start를 통해 최종적으로 getWifiServiceMockable을 호출하게 된다.

 

이게 자료의 오른쪽 2번이다.

 

그리고 여기서 Iwifi 클래스의 getService를 호출하는데,

이 메소드는 제일 아래 코드인데, iwifi.hidl 파일이 빌드될때 자동 생성되는 자바 클래스에 구현된 메소드였다.

 

이 코드는 HW 바인더를 통해 바인드되어 service와 연결이 되었고,

이 과정이 진행됬기 때문에 4번 과정의 createStaIface 메소드로 WifiVendorHal 클래스에 있는 Map 자료구조에 인터페이스 객체를 저장한 뒤, 최종적으로 이 메소드는 이름을 반환하고 있다.

 

 

 

2. SystemServce – HAL Binder 연결 과정 (Supplicant Hal)

 

 

다음은 Supplicant Hal의 바인더를 통한 인터페이스 연결 과정이다.

 

Supplicant hal을 사용하는 setRoamingTrigger에서 hal 객체를 가져오는 방식을 파악해보니 VendorHal과 구조가 매우 유사했다.

 

SupplicantStaIFaceHal에 있는 Map 자료구조에서 동일하게도 인터페이스 명을 통해 Hal 객체를 반환받아 사용하고 있었다.

 

 

그래서 이때는 해당 Map에다 인터페이스를 put하는 코드를 역으로 추적해보았다.

 

SupplicantStaIFaceHal 클래스에서 Hal 인터페이스에 객체를 put하는 메소드를 역추적해보니

VendorHal 분석 할 때의 메소드와 비슷한 지점에서 만나게 되었다.

 

차이점은 SupplicantStaIFaceHalWifi StateScanOnly모드가 시작될 때가 아닌

Wifi가 연결되어 Connectivity 모드가 될 때 수행되는 setup 메소드에서 hal 인터페이스 객체를 생성하는 호출이 시작되고 있었다.

 

아까와 마찬가지로 시계방향으로 흐름이 진행되는데,

먼저 startSupplicant 메소드가 호출되면 내부에서 SupplicantStaIFaceHal 클래스의 Initialize을 호출하게 되고,

이 메소드에서 getServiceManagerMockable 메소드를 호출해서 hidl파일이 빌드 시에 생성되는 getService 메소드를 호출하게 된다.

 

그후 점선 흐름인 setupIface 메소드를 통해 Map 자료구조에 인터페이스를 저장해둔다.

 

이번에는 이 코드도 함께 분석해본 것을 정리해봤다.

 

이 메소드에서는 hal의 버전을 분기처리하여 유연하게 처리할 수 있도록 구현되어 있었고,

이 코드는 최종적으로 버전 설정 후 해당 인터페이스로 바인더 하면서 마무리 되고 있었다.

 

그래서 이전 자료에서 바인드 된 인터페이스는 이 버전처리를 수행할 수 있도록 IServiceManager바인드 한 것이었고,

실질적인 바인드 수행은 이곳에서 마무리 되었음을 확인할 수 있었다.