赞
踩
由于时间跨度过久,这篇博客也由第一篇的基于Android 8升级为了Android11。
本来是想衔接第一篇直接去写AudioService.java里面通知音量改变之后SystemUI里面的处理,但是当我去查看并分析源码的时候,慢慢的慢慢的就把SystemUI的启动过程给看完了,想了一下,于是决定先分析SystemUI的启动过程,然后再去衔接第一篇去分析音量条的处理过程。
在整个系统App里面,SystemUI这个App非常的复杂,在Android11上,Google也用到了Dagger来处理里面丑陋的依赖关系。当时也花了比较久的时间去查看DI这一块,也一起写进去,就当做是一个学习的记录。
如有写的存在问题的地方,还望大家能够指点一下,感激不尽。
于是本篇博客内容分以下三大块:
如果对第一章内容已经了解的同学可以直接享用本篇内容,本篇文章内容较多,希望能仔细阅读。
有了解过Dagger或者使用过Dagger的同学可以看一下第二小节的内容,如果你从来没有接触过Dagger,那么可以跳过第二小节,这个也不影响整体流程。
SystemUI是在frameworks/base/packages/SystemUI/
路径下,以apk的形式预置到了系统中。
SystemUI最开始是在SystemServer.java里面去启动的。
// 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先运行呢?我们从代码中来分析
整个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(); }
这边再来整理一下实际的顺序:
当启动SystemUIService时候就是这样的一个流程。
下面就来看看SystemUI的Application的onCreate()方法。
文章开始有提过,如果没有了解过Dagger的,可能看不懂这一小节,可以直接跳过,对整体流程没有影响。
整个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实例之前或者之后都可以。具体流程这里不去一步一步分析了,可以去跟一下源码流程,比较简单。
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的代码。
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只是解决依赖的一种方法,目前并没有找到一个比较好的方法来处理依赖关系。
// 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的大致流程到这里就结束了。
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等等的实例化对象,在需要使用对应的实例时,会优先从这个类里面去拿到缓存的对象,如果为空才会去创建新的实例化对象。
话不多说,直接上代码
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是类似的。
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的回调接口
先来看看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); } }
接着来看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小节的分析对应上了。
这里我们来分析一下VolumeUI整理流程
整个SystemUI还是比较复杂的,这里只是片面的说明了VolumeUI的代码流程,并没有详细的分析VolumeDialogImpl里面的代码,里面大多都是UI相关的处理,本篇文章侧重去分析了代码流程,如有可以改进的地方还望大家指出,感激不尽~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。