前言
由于时间跨度过久,这篇博客也由第一篇的基于Android 8升级为了Android11。
本来是想衔接第一篇直接去写AudioService.java里面通知音量改变之后SystemUI里面的处理,但是当我去查看并分析源码的时候,慢慢的慢慢的就把SystemUI的启动过程给看完了,想了一下,于是决定先分析SystemUI的启动过程,然后再去衔接第一篇去分析音量条的处理过程。
在整个系统App里面,SystemUI这个App非常的复杂,在Android11上,Google也用到了Dagger来处理里面丑陋的依赖关系。当时也花了比较久的时间去查看DI这一块,也一起写进去,就当做是一个学习的记录。
如有写的存在问题的地方,还望大家能够指点一下,感激不尽。
于是本篇博客内容分以下三大块:
- SystemUI启动过程分析
- SystemUI中Dagger相关代码分析
- VolumeUI流程分析
如果对第一章内容已经了解的同学可以直接享用本篇内容,本篇文章内容较多,希望能仔细阅读。
有了解过Dagger或者使用过Dagger的同学可以看一下第二小节的内容,如果你从来没有接触过Dagger,那么可以跳过第二小节,这个也不影响整体流程。
1.SystemUI启动过程分析
SystemUI是在frameworks/base/packages/SystemUI/
路径下,以apk的形式预置到了系统中。
SystemUI最开始是在SystemServer.java里面去启动的。
1.1 启动SystemUIService
// frameworks/base/services/java/com/android/server/SystemServer.java
public final class SystemServer {
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...
startBootstrapServices();
startCoreServices();
// SystemUIService在这里面启动
startOtherServices();
SystemServerInitThreadPool.shutdown();
...
}
private void startOtherServices() {
....
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManager);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
traceEnd();
...
}
static final void startSystemUi(Context context, WindowManagerService windowManager) {
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
Intent intent = new Intent();
intent.setComponent(pm.getSystemUiServiceComponent());
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
}
这里我们来看一下SystemUI的Component是如何获取到的,先看一下PackageManagerInternal的实现
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
...
// Expose private service for system components to use.
mPmInternal = new PackageManagerInternalImpl();
LocalServices.addService(PackageManagerInternal.class, mPmInternal);
...
}
private class PackageManagerInternalImpl extends PackageManagerInternal {
...
@Override
public ComponentName getSystemUiServiceComponent() {
return ComponentName.unflattenFromString(mContext.getResources().getString(
com.android.internal.R.string.config_systemUIServiceComponent));
}
...
}
}
可以看到PackageManagerInternalImpl是PackageManagerService的内部类,在PackageManagerService的构造函数里面去实例化了PackageManagerInternalImpl,并且添加到了LocalServices里面。
在PackageManagerInternalImpl内部是获取了字符串资源,文件内容如下
<!-- frameworks/base/core/res/res/values/config.xml -->
<!-- SystemUi service component -->
<string name="config_systemUIServiceComponent" translatable="false"
>com.android.systemui/com.android.systemui.SystemUIService</string>
那接下来我们看看PackageManagerService是在哪里去实例化的,这边我找了一下,在PackageManagerService里面有这样一个方法
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
// 这里实例化了PackageManagerService
PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
...
return m;
}
}
可以看到在PackageManagerService里面有一个main的静态方法,在这个方法里面去实例化了PackageManagerService。
最后是在SystemServer里面找到了调用PackageManagerService的main方法的地方,如下:
// frameworks/base/services/java/com/android/server/SystemServer.java
public final class SystemServer {
private void run() {
...
// PackageManagerService在这里面启动
startBootstrapServices();
startCoreServices();
// SystemUIService在这里面启动
startOtherServices();
SystemServerInitThreadPool.shutdown();
...
}
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
...
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
// 启动PackageManagerService
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
...
}
}
可以看到startBootstrapServices是在startOtherServices之前启动的,所以这边就暂时讲完了。
可以知道最终启动的是com.android.systemui.SystemUIService这个service
接下来说个题外话,启动service时,是service先运行,还是Application先运行呢?我们从代码中来分析
1.2 启动Service流程
整个Service的启动流程这边也不细说,这边就说一下ActivityThread.java里面handleCreateService方法的调用过程,该方法代码如下:
// frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
// 创建Context
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
// 创建Application
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
// 创建service的实例
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 调用service的onCreate()方法
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
这边可以看到第15行的注释有说明,先创建了Application的实例,然后创建Service的实例,最后调用了Service的onCreate()方法
我们看看创建Application时,makeApplication方法里面做了哪些操作,代码如下:
// frameworks/base/core/java/android/app/LoadedApk.java
@UnsupportedAppUsage
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
...
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
}
......
}
// frameworks/base/core/java/android/app/Instrumentation.java
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
这边再来整理一下实际的顺序:
- 创建Application实例;
- 调用Application的onCreate()方法;
- 创建Service实例;
- 调用Service的onCreate()方法;
当启动SystemUIService时候就是这样的一个流程。
下面就来看看SystemUI的Application的onCreate()方法。
2.SystemUI中Dagger相关代码分析
文章开始有提过,如果没有了解过Dagger的,可能看不懂这一小节,可以直接跳过,对整体流程没有影响。
2.1 appComponentFactory标签
整个SystemUI大部分的依赖实例都管理在Dependency.java这个类中,我们这篇文章主要是分析VolumeUI,那我们就看看VolumeUI是怎么初始化以及启动的。
在1.2小节中,我们知道了Application先被实例化,然后会调用onCreate方法,但是在我们的AndroidManifest.xml中,Application的标签里面定义了一个属性:
<application
android:name=".SystemUIApplication"
...
tools:replace="android:appComponentFactory"
android:appComponentFactory=".SystemUIAppComponentFactory">
</application>
就是这个appComponentFactory的属性,如果我们指定了相关的类,那么我们appComponentFactory的实现类在创建Application的实例时会收到回调,这个时候我们可以去执行一些初始化的操作,可以在创建Application实例之前或者之后都可以。具体流程这里不去一步一步分析了,可以去跟一下源码流程,比较简单。
2.2 Denpendency依赖实例注入
SystemUIAppComponentFactory继承自AppComponentFactory,重写了instantiateApplicationCompat方法,当系统去创建Application的实例对象时就会回调这个方法。
// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
public class SystemUIAppComponentFactory extends AppComponentFactory {
private static final String TAG = "AppComponentFactory";
@Inject
public ContextComponentHelper mComponentHelper;
public SystemUIAppComponentFactory() {
super();
}
@NonNull
@Override
public Application instantiateApplicationCompat(
@NonNull ClassLoader cl, @NonNull String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Application app = super.instantiateApplicationCompat(cl, className);
if (app instanceof ContextInitializer) {
((ContextInitializer) app).setContextAvailableCallback(
context -> {
SystemUIFactory.createFromConfig(context);
SystemUIFactory.getInstance().getRootComponent().inject(
SystemUIAppComponentFactory.this);
}
);
}
return app;
}
...
public interface ContextAvailableCallback {
void onContextAvailable(Context context);
}
public interface ContextInitializer {
void setContextAvailableCallback(ContextAvailableCallback callback);
}
}
这里看到先调用了super方法拿到Application的实例化对象,然后判断Application是否实现了ContextInitializer这个接口,如果实现了,则去设置Context可用的监听,收到监听之后先创建SystemUIFactory的实例,然后初始化SystemUI的Dagger组件,然后向SystemUIAppComponentFactory注入依赖,这里主要的依赖就是ContextComponentHelper了。
// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
public class SystemUIApplication extends Application implements
SystemUIAppComponentFactory.ContextInitializer {
...
@Override
public void setContextAvailableCallback(
SystemUIAppComponentFactory.ContextAvailableCallback callback) {
mContextAvailableCallback = callback;
}
@Override
public void onCreate() {
...
mContextAvailableCallback.onContextAvailable(this);
mRootComponent = SystemUIFactory.getInstance().getRootComponent();
mComponentHelper = mRootComponent.getContextComponentHelper();
...
}
}
这里可以看到在onCreate里面调用了onContextAvailable方法。
接下来看看SystemUIFactory,这个类主要是用来提供自定义的SystemUI components,
// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
public class SystemUIFactory {
private static final String TAG = "SystemUIFactory";
static SystemUIFactory mFactory;
private SystemUIRootComponent mRootComponent;
public static <T extends SystemUIFactory> T getInstance() {
return (T) mFactory;
}
public static void createFromConfig(Context context) {
if (mFactory != null) {
return;
}
final String clsName = context.getString(R.string.config_systemUIFactoryComponent);
if (clsName == null || clsName.length() == 0) {
throw new RuntimeException("No SystemUIFactory component configured");
}
try {
Class<?> cls = null;
cls = context.getClassLoader().loadClass(clsName);
mFactory = (SystemUIFactory) cls.newInstance();
mFactory.init(context);
} catch (Throwable t) {
Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t);
throw new RuntimeException(t);
}
}
...
public SystemUIFactory() {}
private void init(Context context) {
mRootComponent = buildSystemUIRootComponent(context);
// Every other part of our codebase currently relies on Dependency, so we
// really need to ensure the Dependency gets initialized early on.
Dependency dependency = new Dependency();
mRootComponent.createDependency().createSystemUI(dependency);
dependency.start();
}
}
SystemUIFactory有两个子类:CarSystemUIFactory、TvSystemUIFactory
先说一下SystemUIFactory的createFromConfig做了哪些事情
1.先根据config_systemUIFactoryComponent
拿到class name,然后去实例化。
2.然后调用buildSystemUIRootComponent去获取SystemUI的组件实例
3.创建Dependency实例并绑定到DependencyInjector子组件中,这一步就完成了Dependency里面依赖的所有的对象的注入。
4.然后启动Dependency做一些初始化的操作。
这几步是比较复杂的,接下来看看Dependency的代码。
2.3 Dependency代码分析
Dependency管理着整个SystemUI绝大多数的依赖关系,在Dependency里面通过Lazy来延迟实例的初始化。虽然是延迟初始化,但是预计所有的对象都是在sysui启动期间去创建的。
// frameworks/base/packages/SystemUI/src/com/android/systemui/Dependency.java
/**
* Class to handle ugly dependencies throughout sysui until we determine the
* long-term dependency injection solution.
*/
public class Dependency {
// 通过Class作为key,实例化对象作为value来当做一个缓存
private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
// 通过Class作为key,LazyDependencyCreator接口当做value来延迟初始化对应的实例
private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();
...
// 这里通过Lazy延迟对应的对象的实例化
@Inject Lazy<ActivityStarter> mActivityStarter;
@Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher;
...
protected void start() {
...
// 当调用start方法后,会将Class和延迟创建实例化的接口对象存放进map
mProviders.put(ActivityStarter.class, mActivityStarter::get);
mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
...
}
// 在需要使用实例对象的时候就会调用这个方法
// e.g.
// ActivityStarter starter = Dependency.get(ActivityStarter.class);
@Deprecated
public static <T> T get(Class<T> cls) {
return sDependency.getDependency(cls);
}
protected final <T> T getDependency(Class<T> cls) {
return getDependencyInner(cls);
}
// 通过mDependencies去拿缓存的实例,如果为空则会创建对应的实例
// 并将获取到的实例存放在mDependencies里面当做缓存
private synchronized <T> T getDependencyInner(Object key) {
@SuppressWarnings("unchecked")
T obj = (T) mDependencies.get(key);
if (obj == null) {
obj = createDependency(key);
mDependencies.put(key, obj);
// TODO: Get dependencies to register themselves instead
if (autoRegisterModulesForDump() && obj instanceof Dumpable) {
mDumpManager.registerDumpable(obj.getClass().getName(), (Dumpable) obj);
}
}
return obj;
}
// 通过懒加载回调获取注入的实例
@VisibleForTesting
protected <T> T createDependency(Object cls) {
Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>);
@SuppressWarnings("unchecked")
LazyDependencyCreator<T> provider = mProviders.get(cls);
if (provider == null) {
throw new IllegalArgumentException("Unsupported dependency " + cls
+ ". " + mProviders.size() + " providers known.");
}
return provider.createDependency();
}
...
}
这里就是缓存着整个SystemUI大部分的依赖了,其实可以看到这个类的注释,Google也是说明了Dependency只是解决依赖的一种方法,目前并没有找到一个比较好的方法来处理依赖关系。
2.4 启动Service
// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
public class SystemUIService extends Service {
@Override
public void onCreate() {
super.onCreate();
// Start all of SystemUI
((SystemUIApplication) getApplication()).startServicesIfNeeded();
}
}
通过ContextComponentHelper解析预设的service类名得到实例并启动。
// frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
public class SystemUIApplication {
public void startServicesIfNeeded() {
String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
...
mServices = new SystemUI[services.length];
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];
try {
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
if (obj == null) {
Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
obj = (SystemUI) constructor.newInstance(this);
}
mServices[i] = obj;
}
...
mServices[i].start();
if (mBootCompleteCache.isBootComplete()) {
mServices[i].onBootCompleted();
}
}
mServicesStarted = true;
}
}
在2.2小节已经说明,mComponentHelper单例对象通过Dagger提供。
// frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@Singleton
@Component(modules = {...})
public interface SystemUIRootComponent {
...
@Singleton
ContextComponentHelper getContextComponentHelper();
...
}
ContextComponentHelper是在SystemUIModule中提供的
// frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
public abstract class SystemUIModule {
@Binds
public abstract ContextComponentHelper bindComponentHelper(
ContextComponentResolver componentHelper);
...
}
实际上提供的是ContextComponentResolver的实例。
// frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
@Singleton
public class ContextComponentResolver implements ContextComponentHelper {
private final Map<Class<?>, Provider<Activity>> mActivityCreators;
private final Map<Class<?>, Provider<Service>> mServiceCreators;
private final Map<Class<?>, Provider<SystemUI>> mSystemUICreators;
private final Map<Class<?>, Provider<RecentsImplementation>> mRecentsCreators;
private final Map<Class<?>, Provider<BroadcastReceiver>> mBroadcastReceiverCreators;
@Inject
ContextComponentResolver(Map<Class<?>, Provider<Activity>> activityCreators,
Map<Class<?>, Provider<Service>> serviceCreators,
Map<Class<?>, Provider<SystemUI>> systemUICreators,
Map<Class<?>, Provider<RecentsImplementation>> recentsCreators,
Map<Class<?>, Provider<BroadcastReceiver>> broadcastReceiverCreators) {
mActivityCreators = activityCreators;
mServiceCreators = serviceCreators;
mSystemUICreators = systemUICreators;
mRecentsCreators = recentsCreators;
mBroadcastReceiverCreators = broadcastReceiverCreators;
}
...
private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
try {
Class<?> clazz = Class.forName(className);
Provider<T> provider = creators.get(clazz);
return provider == null ? null : provider.get();
} catch (ClassNotFoundException e) {
return null;
}
}
}
ContextComponentResolver用于缓存各种Activity,Service,SystemUI等等的实例对象,通过class实例从Map查询得到的Provider里取得对应的Service实例。
我们找一下提供VolumeUI实例的地方,是在SystemUIBinder里面提供的
// frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@Module(includes = {...})
public abstract class SystemUIBinder {
@Binds
@IntoMap
@ClassKey(VolumeUI.class)
public abstract SystemUI bindVolumeUI(VolumeUI sysui);
...
}
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@Singleton
public class VolumeUI extends SystemUI {
@Inject
public VolumeUI(Context context, VolumeDialogComponent volumeDialogComponent) {
super(context);
mVolumeComponent = volumeDialogComponent;
}
...
}
这里就是提供的VolumeUI的地方了,到这里我们的Dagger的大致流程到这里就结束了。
2.5 Dagger小结
Dagger的部分依赖处理我们就讲完了。里面涉及到了一些注解,都需要我们去了解实际的作用。
1.Application标签有appComponentFactory属性,可以指定对应的子类,在实例化Application,Service,Activity时都会回调对应的方法,我们可以去做一些初始化的操作。
2.SystemUI Dagger根组件是SystemUIRootComponent这个类,它引用了非常多的module。可以理解为,大部分的依赖都是由SystemUIRootComponent这个类提供的注入。
3.在SystemUIRootComponent类中有Dependency.DependencyInjector createDependency();
这个方法,Dependency.DependencyInjector是在Dependency里面,注解为@Subcomponent,为SystemUIRootComponent的子组件,这个注解的作用就是,即使SystemUIRootComponent没有将实例对象通过方法暴露出去,DependencyInjector也能获取到SystemUIRootComponent里面提供的所有实例的对象。最后将所有的依赖注入到Denpendency里面。
4.在Dependency里面使用到了Lazy,延迟了依赖的对象的初始化,不是一开始就全部初始化,而是在使用的时候才会去初始化,再去通过map缓存起来。
5.ContextComponentResolver这个类缓存了由Dagger提供的Activity、Service、SystemUI等等的实例化对象,在需要使用对应的实例时,会优先从这个类里面去拿到缓存的对象,如果为空才会去创建新的实例化对象。
3.Volume初始化
3.1 启动SystemUI
话不多说,直接上代码
public class SystemUIService extends Service {
...
@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();
}
...
}
Application里面去启动所有的SystemUI,mComponentHelper通过class去拿对应的实例对象,如果为空则去通过Class实例化。
public class SystemUIApplication {
public void startServicesIfNeeded() {
String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
...
mServices = new SystemUI[services.length];
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];
try {
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
if (obj == null) {
Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
obj = (SystemUI) constructor.newInstance(this);
}
mServices[i] = obj;
}
...
mServices[i].start();
if (mBootCompleteCache.isBootComplete()) {
mServices[i].onBootCompleted();
}
}
mServicesStarted = true;
}
}
需要启动的所有Serivce写在配置文件里面
<!-- SystemUI Services: The classes of the stuff to start. -->
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
<item>com.android.systemui.recents.Recents</item>
<item>com.android.systemui.volume.VolumeUI</item>
...
</string-array>
我们需要注意的是,这里使用了模板模式。
SystemUI是一个基类,其中定义了4个抽象或空方法,作为模板指定了子类的行为模式。资源文件中定义的众多子服务类都是SystemUI的子类,既然都继承自SystemUI类,那么这些子类就有一些共同的行为模式,在某些阶段应该有什么表现,只是具体如何表现因不同子类而异。与我们经常用到的AsyncTask是类似的。
3.2 启动VolumeUI
VolumeUI里面没有过多的操作,持有VolumeDialogComponent的引用,在 start的时候做一些初始化的操作。
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@Singleton
public class VolumeUI extends SystemUI {
private VolumeDialogComponent mVolumeComponent;
@Inject
public VolumeUI(Context context, VolumeDialogComponent volumeDialogComponent) {
super(context);
mVolumeComponent = volumeDialogComponent;
}
@Override
public void start() {
boolean enableVolumeUi = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
boolean enableSafetyWarning =
mContext.getResources().getBoolean(R.bool.enable_safety_warning);
mEnabled = enableVolumeUi || enableSafetyWarning;
if (!mEnabled) return;
mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
setDefaultVolumeController();
}
...
private void setDefaultVolumeController() {
DndTile.setVisible(mContext, true);
if (LOGD) Log.d(TAG, "Registering default volume controller");
mVolumeComponent.register();
}
}
两件事情:
1.VolumeDialogComponent里面会去创建我们的音量条UI的实例对象,也就是VolumeDialogImpl
2.setDefaultVolumeController方法会设置AudioService的回调接口
3.3 创建VolumeDialogImpl
先来看看VolumeDialogComponent里面的操作
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@Singleton
public class VolumeDialogComponent implements VolumeComponent, TunerService.Tunable,
VolumeDialogControllerImpl.UserActivityListener{
...
@Inject
public VolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
VolumeDialogControllerImpl volumeDialogController) {
mContext = context;
mKeyguardViewMediator = keyguardViewMediator;
mController = volumeDialogController;
mController.setUserActivityListener(this);
// Allow plugins to reference the VolumeDialogController.
Dependency.get(PluginDependencyProvider.class)
.allowPluginDependency(VolumeDialogController.class);
Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
.withPlugin(VolumeDialog.class)
// 调用createDefault方法
.withDefault(this::createDefault)
// 回调处理
.withCallback(dialog -> {
if (mDialog != null) {
mDialog.destroy();
}
mDialog = dialog;
mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);
}).build();
}
protected VolumeDialog createDefault() {
VolumeDialogImpl impl = new VolumeDialogImpl(mContext);
impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
impl.setAutomute(true);
impl.setSilentMode(false);
return impl;
}
...
}
可以看到VolumeDialogComponent持有VolumeDialogControllerImpl的引用
在初始化的时候,会去创建我们的VolumeDialogImpl,并且会去调用其init方法
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
public class VolumeDialogImpl implements VolumeDialog,
ConfigurationController.ConfigurationListener {
private final H mHandler = new H();
...
public void init(int windowType, Callback callback) {
initDialog();
mAccessibility.init();
// 这里添加了VolumeDialogController里面的回调,
mController.addCallback(mControllerCallbackH, mHandler);
mController.getState();
Dependency.get(ConfigurationController.class).addCallback(this);
}
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
public void onStateChanged(State state) {
onStateChangedH(state);
}
...
};
private final class H extends Handler {
...
private static final int STATE_CHANGED = 7;
public H() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case STATE_CHANGED: onStateChangedH(mState); break;
}
}
}
...
}
这一段代码做了如下几件事情:
1.初始化dialog,设置dialog的布局等等。
2.添加VolumeDialogController的回调,当VolumeDialogController接收到AudioService的回调之后,通过Callback将事件继续通知给Dialog去做出响应的处理。这里的两个参数,一个是回调各个状态的接口,一个是在主线程初始化的Handler。
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@Singleton
public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
protected C mCallbacks = new C();
...
// 添加回调监听
public void addCallback(Callbacks callback, Handler handler) {
mCallbacks.add(callback, handler);
callback.onAccessibilityModeChanged(mShowA11yStream);
}
class C implements Callbacks {
// Callbacks作为key,Handler为value
private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
public void add(Callbacks callback, Handler handler) {
if (callback == null || handler == null) throw new IllegalArgumentException();
mCallbackMap.put(callback, handler);
}
@Override
public void onStateChanged(final State state) {
final long time = System.currentTimeMillis();
final State copy = state.copy();
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
entry.getValue().post(new Runnable() {
@Override
public void run() {
entry.getKey().onStateChanged(copy);
}
});
}
Events.writeState(time, copy);
}
}
...
}
这里C是Callbacks的实现类,并且在内部有一个Map,用来存放对应的Callbacks以及Handler
在VolumeDialogControllerImpl收到来自AudioService的方法之后,就会调用mCallbacks的方法,由于调用的地方是在工作线程,所以在这里通过Handler转化为了UI线程去调用,在对应的实现地方就可以直接改变UI了。
Callbacks代码如下:
// frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@ProvidesInterface(version = VolumeDialogController.VERSION)
@DependsOn(target = StreamState.class)
@DependsOn(target = State.class)
@DependsOn(target = Callbacks.class)
public interface VolumeDialogController {
@ProvidesInterface(version = Callbacks.VERSION)
public interface Callbacks {
int VERSION = 1;
void onShowRequested(int reason);
void onDismissRequested(int reason);
void onStateChanged(State state);
void onLayoutDirectionChanged(int layoutDirection);
void onConfigurationChanged();
void onShowVibrateHint();
void onShowSilentHint();
void onScreenOff();
void onShowSafetyWarning(int flags);
void onAccessibilityModeChanged(Boolean showA11yStream);
void onCaptionComponentStateChanged(Boolean isComponentEnabled, Boolean fromTooltip);
}
}
3.4 注册VolumeController
接着来看setDefaultVolumeController
,这个比较重要
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@Singleton
public class VolumeDialogComponent implements VolumeComponent, TunerService.Tunable,
VolumeDialogControllerImpl.UserActivityListener{
private final VolumeDialogControllerImpl mController;
@Inject
public VolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
VolumeDialogControllerImpl volumeDialogController) {
mController = volumeDialogController;
...
}
...
@Override
public void register() {
mController.register();
}
...
}
VolumeDialogComponent调用VolumeDialogControllerImpl的方法
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@Singleton
public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
...
private AudioManager mAudio;
protected final VC mVolumeController = new VC();
...
public void register() {
setVolumeController();
}
protected void setVolumeController() {
try {
mAudio.setVolumeController(mVolumeController);
} catch (SecurityException e) {
Log.w(TAG, "Unable to set the volume controller", e);
return;
}
}
private final class VC extends IVolumeController.Stub {
@Override
public void volumeChanged(int streamType, int flags) throws RemoteException {
// 收到AudioService调用的方法
mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
}
}
...
}
这里调用AudioManager的setVolumeController方法去设置了音量控制的回调接口。
// frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
implements AccessibilityManager.TouchExplorationStateChangeListener,
AccessibilityManager.AccessibilityServicesStateChangeListener {
private final VolumeController mVolumeController = new VolumeController();
@Override
public void setVolumeController(final IVolumeController controller) {
...
mVolumeController.setController(controller);
}
public static class VolumeController {
private IVolumeController mController;
public void setController(IVolumeController controller) {
mController = controller;
mVisible = false;
}
// 音量发生改变就会调用这个方法
public void postVolumeChanged(int streamType, int flags) {
if (mController == null)
return;
try {
mController.volumeChanged(streamType, flags);
} catch (RemoteException e) {
Log.w(TAG, "Error calling volumeChanged", e);
}
}
...
}
}
在AudioService里面定义了一个内部类VolumeController,持有IVolumeController的引用,当音量发生改变就会调用VolumeController的方法,然后调用IVolumeController的方法,最终回调到SystemUI的VolumeDialogControllerImpl的VC类中。
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@Singleton
public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
...
private final class VC extends IVolumeController.Stub {
@Override
public void volumeChanged(int streamType, int flags) throws RemoteException {
// 收到AudioService调用的方法
mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
}
}
private final class W extends Handler {
private static final int VOLUME_CHANGED = 1;
W(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
...
}
}
}
boolean onVolumeChangedW(int stream, int flags) {
final boolean showUI = shouldShowUI(flags);
final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
boolean changed = false;
if (showUI) {
changed |= updateActiveStreamW(stream);
}
int lastAudibleStreamVolume = getAudioManagerStreamVolume(stream);
changed |= updateStreamLevelW(stream, lastAudibleStreamVolume);
changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
if (changed) {
// 调用mCallbacks的onStateChanged方法
mCallbacks.onStateChanged(mState);
}
...
return changed;
}
...
}
这里的mWork是通过子线程的Looper去初始化的,所以onVolumeChangedW也是在子线程执行的,那么我们mCallbacks的方法也是在子线程执行的,这里的分析也是和3.3小节的分析对应上了。
3.5 VolumeUI小结
这里我们来分析一下VolumeUI整理流程
- VolumeUI持有VolumeDialogComponent的引用,在调用VolumeUI的start方法时,会判断音量条和安全音量提示是否打开,然后会去注册AudioService的监听
- VolumeDialogComponent的构造函数会去创建音量条实例-VolumeDialogImpl,同时VolumeDialogImpl会去执行一些初始化的操作,同时添加VolumeDialogControllerImpl的监听回调。
- 注册AudioService的监听是在VolumeDialogControllerImpl里面注册的,当AudioService进行了调整音量的操作后,VolumeDialogControllerImpl会收到通知,同时会将收到的消息回调给VolumeDialogImpl,做出相应的UI调整,这样就完成了一轮操作。
整个SystemUI还是比较复杂的,这里只是片面的说明了VolumeUI的代码流程,并没有详细的分析VolumeDialogImpl里面的代码,里面大多都是UI相关的处理,本篇文章侧重去分析了代码流程,如有可以改进的地方还望大家指出,感激不尽~