description: “PhoneFactory / Phone 启动流程深度架构设计——Telephony 框架的「大爆炸」初始化, 涵盖 makeDefaultPhone 的单实例保护、CommandsInterface/RIL 创建、UiccController 初始化、SubscriptionManagerService 启动、Phone 创建工厂、TelephonyComponentFactory 依赖注入。”
PhoneFactory 是 Telephony 框架的启动入口,它负责在 phone 进程启动时初始化整个 Telephony 世界。从 RIL 连接的建立、UiccController 的创建、Phone 实例的构造到 SubscriptionManagerService 的启动,所有核心组件都在 makeDefaultPhone() 中按严格的依赖顺序创建。
这个过程如同"创世"——它必须恰好执行一次(double-checked lock),必须按正确的依赖顺序创建所有单例,必须在失败时提供合理的错误处理。
设计理念: PhoneFactory 的设计核心是 严格顺序的初始化依赖链。每个组件的创建都依赖于前面的组件——RIL → UiccController → SubscriptionService → Phone。如果某个环节失败,整个 Telephony 栈将不可用,因此 Google 在这里把错误处理做到了极致。
1. 核心职责
- 单例保护:使用
LocalServerSocket确保 phone 进程只有一个实例 - 组件创建:按依赖顺序创建 RIL、UiccController、SubscriptionService、Phone 等核心组件
- 资源配置:读取系统属性确定网络模式、Modem 数量等
- eSIM 初始化:如果设备支持 eSIM,初始化 EuiccController/EuiccCardController
- Phone 映射:维护
phoneId → Phone的数组索引映射
2. 核心类与源码锚点
- [PhoneFactory.java](file:///d:/Resource%20Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java):启动入口。包含
makeDefaultPhone()方法和所有静态组件引用。 - [GsmCdmaPhone.java](file:///d:/Resource%20Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java):通用的 GSM/CDMA Phone 实现。创建后关联 ServiceStateTracker、DataNetworkController 等。
- [TelephonyComponentFactory.java](file:///d:/Resource%20Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/TelephonyComponentFactory.java):依赖注入工厂。允许 OEM 通过
inject()替换默认组件实现。 - [ProxyController.java](file:///d:/Resource%20Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/ProxyController.java):多 SIM 代理控制器。
- [PhoneSwitcher.java](file:///d:/Resource%20Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/data/PhoneSwitcher.java):数据连接的 Phone 切换器。
3. Google 设计技巧深入分析
3.1 LocalServerSocket 单实例保护
for(;;) {
boolean hasException = false;
retryCount++;
try {
new LocalServerSocket("com.android.internal.telephony");
} catch (java.io.IOException ex) {
hasException = true;
}
if (!hasException) {
break;
} else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
throw new RuntimeException("PhoneFactory probably already running");
} else {
try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); // 2 秒
} catch (InterruptedException er) {
}
}
}
Google设计技巧 #1 — UNIX Domain Socket 的单实例保护:
使用LocalServerSocket("com.android.internal.telephony")而非传统的文件锁或 PID 文件。这是因为 Android 中 phone 进程可能被 kill 后重启——LocalServerSocket是内核管理的资源,当进程死亡时内核自动释放 socket,下一个 phone 实例可以成功创建。而如果 phone 进程已运行,创建同名 socket 会抛出IOException,从而检测到重复启动。同时使用 3 次重试 + 2 秒间隔的策略,处理进程重启时 socket 尚未完全释放的竞态窗口。
3.2 严格顺序的初始化依赖链
public static void makeDefaultPhone(Context context, @NonNull FeatureFlags featureFlags) {
synchronized (sLockProxyPhones) {
if (!sMadeDefaults) {
sContext = context;
// 1. 创建 TelephonyDevController
TelephonyDevController.create();
// 2. 获取 Modem 数量
int numPhones = TelephonyManager.getDefault().getActiveModemCount();
// 3. 创建 CommandsInterface (RIL) 数组
sCommandsInterfaces = new RIL[numPhones];
for (int i = 0; i < numPhones; i++) {
sCommandsInterfaces[i] = new RIL(context, ...);
}
// 4. 创建 RadioConfig
final RadioConfig radioConfig = RadioConfig.make(context, ...);
// 5. 创建 UiccController (单例)
sUiccController = UiccController.make(context<


1458

被折叠的 条评论
为什么被折叠?



