Read The Fucking Source Code.
—— Linus
站在’巨人’的肩膀上开始自己的旅途。—— 佚名
愉快的周末,从打开💻开始,到骑行归来结束。—— 佚名
忙忙碌碌又一周,城市的快节奏似乎是时间的轮盘上了润滑剂比以往转得更快,早上进入地铁看天空还是那么明亮,晚上踏出地铁口已是昏暗。
工作日确实忙绿,然而周末呢?
上午还在养精蓄锐 (懒床)
中午便是一天的开始
下午又能干嘛 (摆烂一下午)
晚上呢 (继续摆烂)
你说这一周能过得不快吗 🤔
文章系列
注:
本系列文章源码基于 Android 11-r21 master 分支
源码阅读可是一项耗时、费力的‘大工程’,对于大多数人来说可能是多么的枯燥无味,为了消除枯燥感,尝试接触新鲜事物可是一个良好的治疗药方,前三篇都是在看 Android 启动,现在不妨在下一次开始之前看看别的东西 ——— package
,看看这里面都是些什么?
对于系统应用就就不过多展开,这种更适合当前从事应用开发的同学,我们就挑拣几个感兴趣的模块稍微展开。
packages
—— apps 系统应用
—— basicSmsReceiver
1.1 注册一个广播接收器 sms reciever,接受回调中通过解析 intent -> bundle -> puts 获得短信数据
1.2 收到的每一条短信都需要一个唯一的通知ID,notificationId(先猜测这是通知渠道ID),通知点击事件将通过 pendingIntent 跳转到短信内容页面
1.3 这个通知ID使用 SP 存储,下一次接收到通知时候自增,最大值不能超过最大阈值 32765(超过将重置)
—— bluetooth
1.1 蓝牙实现还是比较底层的,最终会接触到硬件设备,那么这里需要 jni 调用,此前需要初始化 native
1.2 蓝牙数据使用 room 框架做数据的 CURD 操作,主要数据是蓝牙地址、上一次激活时间
1.3 设备管理,负责监听设备和蓝牙之间的连接、断开事件
1.4 蓝牙服务是由多个子服务、通讯规范整合形成的,比如我们知道的有:蓝牙音频传输协议服务(A2PD)、音量控制服务、音视频远程控制规范(AVRCP)等等
1.5 蓝牙是如何通讯的?a2dp —— a2dpshink 简单理解是 C——S 通讯(物联网应该接触到比较多,我们就略过吧)
1.6 关键代码还是在 jni,这里就不展开了
—— browser2
1.1 【略】一个用于测试的 webview,构建生产环境使用的浏览器请参考链接;浏览器可又是一个大型项目——Chromium
—— calendar
1.1 好家伙,此模块用 kotlin 写,差点看不懂了 kt 的语法了解的还是太少,不影响我们粗略阅读
1.2 日历除了看日期基本功能,还有其他的附加功能,比如闹钟提醒需要 AlarmScheduler,事件通知需要 notification
1.3 日历在此前是我们遇到的第一个 UI 界面比较多的应用,对于应用开发者来说看看官方如何实现‘日历’可有一定参考;如何巧用列表控件、数据适配器。
—— camera2
1.1 相机主要的是图片,图片到底就是像素——一个多维的字节数组,对图片的处理最终既是对每一个像素的处理、转变,实际处理还是在 native
1.2 【略】主要涉及对图片和音频的处理,如果当前从事相关开发我觉得可以继续往下看看,目前先略过(主要是代码不少啊😭)
—— car
—— carrierConfig
—— cellBroadcastReceiver
—— certInstaller
—— contacts
—— deskClock
—— DevCamera
—— dialer
—— documentUI
—— emergencyInfo
—— Gallery2
—— Gallery
—— HTMLViewer
—— keyChain
—— Launcher3 【重点!重点!重点!】
1.1 桌面应用,不就是我们看到的手机桌面嘛!看名称是 Launcher3 这个是原声系统的,如果你在友商手机看,这个名字可能是 ******.Launcher;
原生的桌面应用可能太丑了,厂商通常都会开发自己的桌面应用程序,美化桌面,吸引用户————爱美之心。
1.2 看 Androidmanifest 只有一个activity,便是桌面程序的主界面 com.android.launcher3.Launcher,这是一个可以拖拽的、有状态的 activity
1.3 UI 界面我们不关心如何,关注的是应用数据 AppInfo 来源,数据是如何获取到的?数据都包含了哪些内容(应用程序直接找 model 模块——MVC、MVVM、MVP)?
——【ItemInfo】
ID:每一条数据在数据库的ID
type:应用程序、文件夹、部件、自定义部件、快捷方式
screenID:桌面ID,比如应用在桌面快速启动可以通过这个ID找到对应的应用程序启动数据
cellX/Y:坐标(桌面可以看作是一个二维网格)
title:最明显的应用图标或者文件夹名称、文件名称(桌面程序不仅仅是我们理解的那个只有只用应用图标的桌面)
componentName:这个就比较重要了,通常携带目标界面的启动类和必要数据
userHandle:通过 framework/base/core/java/android/os/Process 的 myUserHandle 方法赋值;
userHandle —— 当前进程的用户句柄,系统缓存的实例,是在 zygote 进程中被创建。
user 即是用户,这里的用户划分是什么:系统用户、所有用户、当前活动用户(大概意思就是根据 uid 获取特定的当前进程合适的 handle 来发送消息)
——【FloderInfo】
lableState:标签
workspaceItemInfo:工作目录下可启动的应用程序(父类是 ItemInfoWithIcon)
——【LauncherAppWidgetInfo】
intent:
compotentName:能够启动的,基本都包含着两个
——【ItemInfoWithIcon】
bitmap:作为应用程序,应用图标必不可少
process:应用下载进度,最大 100
——【AppInfo】
intent:启动程序的常规方式就是通过 intent
——【PackageItemInfo】
packagename:应用层开发者也知道 Android 在应用层有提供通过包名启动程序的接口
1.4 说到底,数据从那里来?【重点!这才是本次真正关注的点】
packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java 就是线程需要执行的任务;直接看 run 方法,加载任务大概做了这些事:
1.4.1 loadWorkspace:默认从当前应用收藏夹 favorites uri 通过 contentResolve 解析数据(数据解析部分有点复杂不展开了)
1.4.2 loadAllApps:需要的数据是 LauncherActivityInfo,实际获取数据的转到了 frameworks/base/core/java/android/content/pm/LauncherApps.java;
这是一个 AIDL 接口,ILauncherApps.aidl 实现类是 LauncherAppsService;获取到的事 resolveInfo 再通过 convertToActivitList 获得最终数据
(流程比较长点到为止,其实就是查询应用信息在组装转换为最后需要的)
1.4.3 loadDeepShortcuts: shortcut 快捷方式;通过 usermanager getUserProfiles 解析获得
(framework/base/core/java/android/os/UserManager.java),实际上就是当前进程的 UserHandle
1.4.4 widgetsModel.update(mApp, null):从应用中更新或者解析创建桌面部件
/*到这里,桌面需要显示的应用信息已经获得,后面就是通过适配器把数据填充、显示,最后就是我们能看到的设备桌面*/
—— legacyCamera
—— managedProvisioning
—— messaging
—— music
—— musicFX
—— nfc
—— onDeviceAppPrediction
—— oneTimeInitializer
—— phoneCommon
—— protips
—— provision
—— quickAccessWallet
—— quickSearchBox
—— safetyRegulartoryInfo
—— sampleLocationAttribution
—— secureElement
—— settings
—— settingsIntelligence
—— soundRecorder
—— stk
—— storageManager
—— tag
—— terminal
—— themepicker
—— timeZoneData
—— TimeZoneUpdate
—— traceur
—— tv
—— tvSettings
—— universalMediaPlayer
—— wallpaperPicker
—— wallpaperPicker2
—— inputmethods 输入法
—— modules
—— providers 数据来源(其实就是对操作数据库,只是 CURD 操作系统封装为内容提供者——contentprovider,有一部分系统应用的数据源内容提供者,比如:联系人、日历)
—— blocedNumberProvider 被屏蔽的电话提供者(数据库:blockednumbers.db)
—— bookmarkProvider 书签提供者(一看代码无任何实现,留着估计是为了兼容考虑)
—— calenderProvider 日历(数据库:calender.db;包含日历闹钟提醒、日历信息更新等)
—— contactsProvider 联系人
—— downloadProvider 接收器——通过系统广播接受,通知——notificationManager,扫描——mediaScannerConnectionClient,
存储——fileSystemProvider,线程——发起下载请求、文件磁盘持久化
(数据库:downloads.db;JobService——特定条件下执行的后台服务,比如:下载并安装完毕需删除安装包,删除的不仅是安装包文件还有数据库中的记录)
—— mediaProvider 多媒体(媒体访问往往需要权限,提供音频播放、图片视频选择界面)
—— partnerBookmarksProvider 合作伙伴书签?不太了解
—— telephonyProvider 电话(运营商信息:CarrierInformation.db 运营商标识:carrierIdentification.d 短信内容:mmssms.db 电话内容:telephony.db)
—— tvProvider 电视(机顶盒? 数据库:tv.db)
—— userDictionaryProvider 用户字典
—— screensavers 屏保
—— basic 基础工具(只有一个颜色选择)
—— phototable 界面 activity、数据源 source、适配器 adapter
—— services
—— alternativeNetworkAccess 网络相关
—— builtinPrint 打印服务
—— car 车载服务
—— mms 多媒体消息(multimedia messaging service)
—— mtp 媒体传输协议(media transfer protocol)
—— telecomm 通讯工具
—— bluetooth 蓝牙
—— callfiltering 电话过滤
—— callrederiction 电话重定向
—— telephone 电话服务
—— wallpapers 壁纸
—— live wallpapers 实时壁纸