1.安卓包管理机制之PackageInstaller安装APK
2.面试中常被问到的Framework 底层原理!
3.debugåreleaseçåºå«
安卓包管理机制之PackageInstaller安装APK
前言
本文继续探讨Android包管理机制中的PackageInstaller组件,特别是其在安装APK文件时的运作机制。讨论基于Android 8.0版本的源码。
在PackageInstallerActivity中,调用startInstallConfirm方法后,充值 审核 源码安装确认界面显现给用户,用户选择继续安装应用程序时,触发PackageInstallerActivity的onClick方法。该方法处理确定和取消按钮的交互,主要关注确定按钮的响应,调用startInstall方法,DLL翻译源码从而跳转至InstallInstalling界面,关闭当前Activity。
在InstallInstalling界面,根据保存的mSessionId和mInstallId进行安装处理。如果之前有保存信息,会根据mInstallId注册观察者,接收安装事件的回调,无论成功与否均关闭当前Activity。若无保存信息,则创建SessionParams,解析APK的护眼app源码参数,注册观察者,生成mInstallId,最终与PackageInstallerService进行交互。
在InstallInstalling的onResume方法中,根据mSessionId获取SessionInfo,创建并执行InstallingAsyncTask,将APK信息通过IO流写入PackageInstaller.Session。onPostExecute方法中创建PendingIntent,并通过PackageInstaller.Session的commit方法发送,最终调用PackageInstallerSession的commit方法,进入Java框架层处理。.net源码wms
在Java框架层,通过PackageInstallerSession的commit方法,将APK信息封装为PackageInstallObserverAdapter,并通过Handler发送MSG_COMMIT消息。该消息处理程序获取IPackageInstallObserver2类型的观察者,调用commitLocked方法,进一步调用PMS的installStage方法。如果在PMS中出现异常,会通过dispatchSessionFinished方法,调用观察者的onPackageInstalled方法,将异常信息回调给PackageInstallObserverAdapter。持仓指标源码
总结而言,PackageInstaller安装APK的过程分为两个关键步骤:调用PackageInstallerActivity的onClick方法启动安装流程,然后在Java框架层中,通过PMS处理APK安装的具体细节。后续文章将深入探讨PMS中的复杂处理过程。
面试中常被问到的Framework 底层原理!
Android 开发领域对技术的要求日益提高,不再局限于对四大组件和基础开发技能的了解。现在的公司更加注重候选人的技术深度和对源码原理的理解,尤其在大型企业的面试中,对 Android Framework 底层原理的考察尤为突出。
Android 的进程通信机制主要通过 Binder 实现,而线程通信则依赖于 Handler。这两个机制不仅是 Android 开发的基石,也是面试中的重要知识点。
以 Handler 为例,了解其源码结构有助于深入理解相关概念。
Binder 作为 Android 的主要跨进程通信方式,包括 BinderProxy、BpBinder 等多种实体,以及 ProcessState、IPCThreadState 等封装。它贯穿 Java、Native 层,涉及用户态、内核态,与 Service、AIDL 等紧密相关,向下则与 mmap、Binder 驱动设备相连,是一个庞大而复杂的机制。
面试中,面试官可能会问及基于 mmap 的拷贝实现方式。通过图形化解释,我们可以更好地理解这一过程:Client 和 Server 处于不同进程,拥有不同的虚拟地址规则,无法直接通信。通过映射页框,可以将物理内存分别与 Client 和 Server 的虚拟内存块进行映射,实现一次数据拷贝。
精通 Framework 不仅需要对底层原理有深入了解,还需要将 Framework 知识应用于实践,如 Android App 的启动机制、AMS、PMS、WMS 等。
许多学习者和实践者在 Android Framework 面临困扰,但很少人能够逆向分析并找到最优解决方案。Framework 是 Android 开发的深水区,也是衡量程序员能力的重要标准。
为了帮助大家节省学习周期,我整理了《Android Framework 源码解析》这份文档,希望对大家在技术道路上有所帮助。完整版文档已在 GitHub 收录,请参考学习。
debugåreleaseçåºå«
Debugé常称为è°è¯çæ¬ï¼å®å å«è°è¯ä¿¡æ¯ï¼å¹¶ä¸ä¸ä½ä»»ä½ä¼åï¼ä¾¿äºç¨åºåè°è¯ç¨åºãRelease称为åå¸çæ¬ï¼å®å¾å¾æ¯è¿è¡äºåç§ä¼åï¼ä½¿å¾ç¨åºå¨ä»£ç 大å°åè¿è¡é度ä¸é½æ¯æä¼çï¼ä»¥ä¾¿ç¨æ·å¾å¥½å°ä½¿ç¨ã
Debug å Release ççæ£ç§å¯ï¼å¨äºä¸ç»ç¼è¯é项ãä¸é¢ååºäºåå«é对äºè çé项ï¼å½ç¶é¤æ¤ä¹å¤è¿æå ¶ä»ä¸äºï¼å¦/Fd /Foï¼ä½åºå«å¹¶ä¸éè¦ï¼é常ä»ä»¬ä¹ä¸ä¼å¼èµ· Release çé误ï¼å¨æ¤ä¸è®¨è®ºï¼
Debug çæ¬
åæ° å«ä¹
/MDd /MLd æ /MTd ä½¿ç¨ Debug runtime library (è°è¯çæ¬çè¿è¡æ¶å»å½æ°åº)
/Od å ³éä¼åå¼å ³
/D "_DEBUG" ç¸å½äº #define _DEBUG,æå¼ç¼è¯è°è¯ä»£ç å¼å ³ (主è¦é对assertå½æ°)
/ZI å建 Edit and continue(ç¼è¾ç»§ç»)æ°æ®åºï¼è¿æ ·å¨è°è¯è¿ç¨ä¸å¦æä¿®æ¹äºæºä»£ç ä¸ééæ°ç¼è¯
/GZ å¯ä»¥å¸®å©æè·å åé误
/Gm æå¼æå°åéé¾æ¥å¼å ³ï¼ åå°é¾æ¥æ¶é´
Release çæ¬
åæ° å«ä¹
/MD /ML æ /MT 使ç¨åå¸çæ¬çè¿è¡æ¶å»å½æ°åº
/O1 æ /O2 ä¼åå¼å ³ï¼ä½¿ç¨åºæå°ææå¿«
/D "NDEBUG" å ³éæ¡ä»¶ç¼è¯è°è¯ä»£ç å¼å ³ (å³ä¸ç¼è¯assertå½æ°)
/GF å并éå¤çåç¬¦ä¸²ï¼ å¹¶å°å符串常éæ¾å°åªè¯»å åï¼ é²æ¢è¢«ä¿®æ¹
å®é ä¸ï¼Debug å Release 并没ææ¬è´¨ççéï¼ä»ä»¬åªæ¯ä¸ç»ç¼è¯é项çéåï¼ç¼è¯å¨åªæ¯æç §é¢å®çé项è¡å¨ãäºå®ä¸ï¼æ们çè³å¯ä»¥ä¿®æ¹è¿äºé项ï¼ä»èå¾å°ä¼åè¿çè°è¯çæ¬ææ¯å¸¦è·è¸ªè¯å¥çåå¸çæ¬ã
åªäºæ åµä¸ Release çä¼åºé
æäºä¸é¢çä»ç»ï¼æ们åæ¥éä¸ªå¯¹ç §è¿äºé项çç Release çé误æ¯ææ ·äº§çç
1ãRuntime Libraryï¼é¾æ¥åªç§è¿è¡æ¶å»å½æ°åºé常åªå¯¹ç¨åºçæ§è½äº§çå½±åãè°è¯çæ¬ç Runtime Library å å«äºè°è¯ä¿¡æ¯ï¼å¹¶éç¨äºä¸äºä¿æ¤æºå¶ä»¥å¸®å©åç°é误ï¼å æ¤æ§è½ä¸å¦åå¸çæ¬ãç¼è¯å¨æä¾ç Runtime Library é常å¾ç¨³å®ï¼ä¸ä¼é æ Release çé误ï¼åæ¯ç±äº Debug ç Runtime Library å 强äºå¯¹é误çæ£æµï¼å¦å å ååé ï¼ææ¶ä¼åºç° Debug æéä½ Release æ£å¸¸çç°è±¡ãåºå½æåºçæ¯ï¼å¦æ Debug æéï¼å³ä½¿ Release æ£å¸¸ï¼ç¨åºè¯å®æ¯æ Bug çï¼åªä¸è¿å¯è½æ¯ Release ççæ次è¿è¡æ²¡æ表ç°åºæ¥èå·²ã
2ãä¼åï¼è¿æ¯é æé误ç主è¦åå ï¼å ä¸ºå ³éä¼åæ¶æºç¨åºåºæ¬ä¸æ¯ç´æ¥ç¿»è¯çï¼èæå¼ä¼ååç¼è¯å¨ä¼ä½åºä¸ç³»åå设ãè¿ç±»é误主è¦æ以ä¸å ç§ï¼
1. 帧æé(Frame Pointer)çç¥ï¼ç®ç§°FPOï¼ï¼å¨å½æ°è°ç¨è¿ç¨ä¸ï¼ææè°ç¨ä¿¡æ¯ï¼è¿åå°åãåæ°ï¼ä»¥åèªå¨åéé½æ¯æ¾å¨æ ä¸çãè¥å½æ°ç声æä¸å®ç°ä¸åï¼åæ°ãè¿åå¼ãè°ç¨æ¹å¼ï¼ï¼å°±ä¼äº§çé误ï¼ä½ Debug æ¹å¼ä¸ï¼æ ç访é®éè¿ EBP å¯åå¨ä¿åçå°åå®ç°ï¼å¦æ没æåçæ°ç»è¶çä¹ç±»çé误ï¼ææ¯è¶çâä¸å¤âï¼ï¼å½æ°é常è½æ£å¸¸æ§è¡ï¼Release æ¹å¼ä¸ï¼ä¼åä¼çç¥ EBP æ åºåæéï¼è¿æ ·éè¿ä¸ä¸ªå ¨å±æé访é®æ å°±ä¼é æè¿åå°åé误æ¯ç¨åºå´©æºã
C++ ç强类åç¹æ§è½æ£æ¥åºå¤§å¤æ°è¿æ ·çé误ï¼ä½å¦æç¨äºå¼ºå¶ç±»å转æ¢ï¼å°±ä¸è¡äºãä½ å¯ä»¥å¨ Release çæ¬ä¸å¼ºå¶å å ¥/Oy-ç¼è¯é项æ¥å ³æ帧æéçç¥ï¼ä»¥ç¡®å®æ¯å¦æ¤ç±»é误ãæ¤ç±»é误é常æï¼MFC æ¶æ¯ååºå½æ°ä¹¦åé误ãæ£ç¡®çåºä¸ºï¼
afx_msg LRESULT OnMessageOwn
(WPARAM wparam, LPARAM lparam);
ON_MESSAGE å®å å«å¼ºå¶ç±»å转æ¢ãé²æ¢è¿ç§é误çæ¹æ³ä¹ä¸æ¯éå®ä¹ ON_MESSAGE å®ï¼æä¸å代ç å å° stdafx.h ä¸ï¼å¨#include "afxwin.h"ä¹åï¼,å½æ°åå½¢é误æ¶ç¼è¯ä¼æ¥éã
#undef ON_MESSAGE
#define ON_MESSAGE(message, memberFxn) /
{
message, 0, 0, 0, AfxSig_lwl, /
(AFX_PMSG)(AFX_PMSGW)
(static_cast< LRESULT (AFX_MSG_CALL /
CWnd::*)(WPARAM, LPARAM) > (&memberFxn)
},
2. volatile ååéï¼volatile åè¯ç¼è¯å¨è¯¥åéå¯è½è¢«ç¨åºä¹å¤çæªç¥æ¹å¼ä¿®æ¹ï¼å¦ç³»ç»ãå ¶ä»è¿ç¨å线ç¨ï¼ãä¼åç¨åºä¸ºäºä½¿ç¨åºæ§è½æé«ï¼å¸¸æä¸äºåéæ¾å¨å¯åå¨ä¸ï¼ç±»ä¼¼äº register å ³é®åï¼ï¼èå ¶ä»è¿ç¨åªè½å¯¹è¯¥åéæå¨çå åè¿è¡ä¿®æ¹ï¼èå¯åå¨ä¸çå¼æ²¡åã
å¦æä½ çç¨åºæ¯å¤çº¿ç¨çï¼æè ä½ åç°æ个åéçå¼ä¸é¢æçä¸ç¬¦èä½ ç¡®ä¿¡å·²æ£ç¡®ç设置äºï¼åå¾å¯è½éå°è¿æ ·çé®é¢ãè¿ç§é误ææ¶ä¼è¡¨ç°ä¸ºç¨åºå¨æå¿«ä¼ååºéèæå°ä¼åæ£å¸¸ãæä½ è®¤ä¸ºå¯ççåéå ä¸ volatile è¯è¯ã
3. åéä¼åï¼ä¼åç¨åºä¼æ ¹æ®åéç使ç¨æ åµä¼ååéãä¾å¦ï¼å½æ°ä¸æä¸ä¸ªæªè¢«ä½¿ç¨çåéï¼å¨ Debug çä¸å®æå¯è½æ©çä¸ä¸ªæ°ç»è¶çï¼èå¨ Release çä¸ï¼è¿ä¸ªåéå¾å¯è½è¢«ä¼åè°ï¼æ¤æ¶æ°ç»è¶çä¼ç ´åæ ä¸æç¨çæ°æ®ãå½ç¶ï¼å®é çæ åµä¼æ¯è¿å¤æå¾å¤ãä¸æ¤æå ³çé误æéæ³è®¿é®ï¼å æ¬æ°ç»è¶çãæéé误çãä¾å¦ï¼
void fn(void)
{
int i;
i = 1;
int a[4];
{
int j;
j = 1;
}
a[-1] = 1;
//å½ç¶é误ä¸ä¼è¿ä¹ææ¾ï¼ä¾å¦ä¸æ æ¯åé
a[4] = 1;
}
j è½ç¶å¨æ°ç»è¶çæ¶å·²åºäºä½ç¨åï¼ä½å ¶ç©ºé´å¹¶æªæ¶åï¼å è i å j å°±ä¼æ©çè¶çãè Release çç±äº iãj 并æªå ¶å¾å¤§ä½ç¨å¯è½ä¼è¢«ä¼åæï¼ä»è使æ è¢«ç ´åã
3. DEBUG ä¸ NDEBUG ï¼å½å®ä¹äº _DEBUG æ¶ï¼assert() å½æ°ä¼è¢«ç¼è¯ï¼è NDEBUG æ¶ä¸è¢«ç¼è¯ãæ¤å¤ï¼TRACE() å®çç¼è¯ä¹å _DEBUG æ§å¶ã
ææè¿äºæè¨é½åªå¨ Debugçä¸æ被ç¼è¯ï¼èå¨ Release çä¸è¢«å¿½ç¥ãå¯ä¸çä¾å¤æ¯ VERIFY()ãäºå®ä¸ï¼è¿äºå®é½æ¯è°ç¨äºassert()å½æ°ï¼åªä¸è¿éå äºä¸äºä¸åºæå ³çè°è¯ä»£ç ãå¦æä½ å¨è¿äºå®ä¸å å ¥äºä»»ä½ç¨åºä»£ç ï¼èä¸åªæ¯å¸å°è¡¨è¾¾å¼ï¼ä¾å¦èµå¼ãè½æ¹ååéå¼çå½æ°è°ç¨çï¼ï¼é£ä¹Releaseçé½ä¸ä¼æ§è¡è¿äºæä½ï¼ä»èé æé误ãåå¦è å¾å®¹æç¯è¿ç±»é误ï¼æ¥æ¾çæ¹æ³ä¹å¾ç®åï¼å 为è¿äºå®é½å·²å¨ä¸é¢ååºï¼åªè¦å©ç¨ VC++ ç Find in Files åè½å¨å·¥ç¨æææ件ä¸æ¾å°ç¨è¿äºå®çå°æ¹åä¸ä¸æ£æ¥å³å¯ãå¦å¤ï¼æäºé«æå¯è½è¿ä¼å å ¥ #ifdef _DEBUG ä¹ç±»çæ¡ä»¶ç¼è¯ï¼ä¹è¦æ³¨æä¸ä¸ã
顺便å¼å¾ä¸æçæ¯VERIFY()å®ï¼è¿ä¸ªå®å è®¸ä½ å°ç¨åºä»£ç æ¾å¨å¸å°è¡¨è¾¾å¼éãè¿ä¸ªå®é常ç¨æ¥æ£æ¥ Windows APIçè¿åå¼ãæäºäººå¯è½ä¸ºè¿ä¸ªåå è滥ç¨VERIFY()ï¼äºå®ä¸è¿æ¯å±é©çï¼å 为VERIFY()è¿åäºæè¨çææ³ï¼ä¸è½ä½¿ç¨åºä»£ç åè°è¯ä»£ç å®å ¨å离ï¼æç»å¯è½ä¼å¸¦æ¥å¾å¤éº»ç¦ãå æ¤ï¼ä¸å®¶ä»¬å»ºè®®å°½éå°ç¨è¿ä¸ªå®ã
4. /GZ é项ï¼è¿ä¸ªé项ä¼å以ä¸è¿äºäºï¼
1. åå§åå åååéãå æ¬ç¨ 0xCC åå§åææèªå¨åéï¼0xCD ( Cleared Data ) åå§åå ä¸åé çå åï¼å³å¨æåé çå åï¼ä¾å¦ new ï¼ï¼0xDD ( Dead Data ) å¡«å 已被éæ¾çå å åï¼ä¾å¦ delete ï¼ï¼0xFD( deFencde Data ) åå§ååä¿æ¤çå åï¼debug çå¨å¨æåé å åçååå å ¥ä¿æ¤å å以é²æ¢è¶ç访é®ï¼ï¼å ¶ä¸æ¬å·ä¸çè¯æ¯å¾®è½¯å»ºè®®çå©è®°è¯ãè¿æ ·åç好å¤æ¯è¿äºå¼é½å¾å¤§ï¼ä½ä¸ºæéæ¯ä¸å¯è½çï¼èä¸ ä½ç³»ç»ä¸æéå¾å°æ¯å¥æ°å¼ï¼å¨æäºç³»ç»ä¸å¥æ°çæéä¼äº§çè¿è¡æ¶é误ï¼ï¼ä½ä¸ºæ°å¼ä¹å¾å°éå°ï¼èä¸è¿äºå¼ä¹å¾å®¹æ辨认ï¼å æ¤è¿å¾æå©äºå¨ Debug çä¸åç° Release çæä¼éå°çé误ãè¦ç¹å«æ³¨æçæ¯ï¼å¾å¤äººè®¤ä¸ºç¼è¯å¨ä¼ç¨0æ¥åå§ååéï¼è¿æ¯é误çï¼èä¸è¿æ ·å¾ä¸å©äºæ¥æ¾é误ï¼ã
2. éè¿å½æ°æéè°ç¨å½æ°æ¶ï¼ä¼éè¿æ£æ¥æ æééªè¯å½æ°è°ç¨çå¹é æ§ãï¼é²æ¢åå½¢ä¸å¹é ï¼
3. å½æ°è¿ååæ£æ¥æ æéï¼ç¡®è®¤æªè¢«ä¿®æ¹ãï¼é²æ¢è¶ç访é®ååå½¢ä¸å¹é ï¼ä¸ç¬¬äºé¡¹åå¨ä¸èµ·å¯å¤§è´æ¨¡æ帧æéçç¥ FPO ï¼é常 /GZ é项ä¼é æ Debug çåºéè Release çæ£å¸¸çç°è±¡ï¼å 为 Release çä¸æªåå§åçåéæ¯éæºçï¼è¿æå¯è½ä½¿æéæåä¸ä¸ªææå°åèæ©çäºéæ³è®¿é®ãé¤æ¤ä¹å¤ï¼/Gm/GFçé项é æé误çæ åµæ¯è¾å°ï¼èä¸ä»ä»¬çæææ¾èæè§ï¼æ¯è¾å®¹æåç°ã
ææ ·âè°è¯â Release ççç¨åº
éå°Debugæåä½Release失败ï¼æ¾ç¶æ¯ä¸ä»¶å¾æ²®ä¸§çäºï¼èä¸å¾å¾æ ä»ä¸æãå¦æä½ çäºä»¥ä¸çåæï¼ç»åé误çå ·ä½è¡¨ç°ï¼å¾å¿«æ¾åºäºé误ï¼åºç¶å¾å¥½ãä½å¦æä¸æ¶æ¾ä¸åºï¼ä»¥ä¸ç»åºäºä¸äºå¨è¿ç§æ åµä¸ççç¥ã
1. åé¢å·²ç»æè¿ï¼DebugåReleaseåªæ¯ä¸ç»ç¼è¯é项çå·®å«ï¼å®é ä¸å¹¶æ²¡æä»ä¹å®ä¹è½åºåäºè ãæ们å¯ä»¥ä¿®æ¹Releaseççç¼è¯é项æ¥ç¼©å°é误èå´ãå¦ä¸æè¿°ï¼å¯ä»¥æRelease çé项é个æ¹ä¸ºä¸ä¹ç¸å¯¹çDebugé项ï¼å¦/MDæ¹ä¸º/MDdã/O1æ¹ä¸º/Odï¼æè¿è¡æ¶é´ä¼åæ¹ä¸ºç¨åºå¤§å°ä¼åã注æï¼ä¸æ¬¡åªæ¹ä¸ä¸ªé项ï¼çæ¹åªä¸ªé项æ¶é误æ¶å¤±ï¼å对åºè¯¥é项ç¸å ³çé误ï¼é对æ§å°æ¥æ¾ãè¿äºé项å¨Project/Settings...ä¸é½å¯ä»¥ç´æ¥éè¿å表éåï¼é常ä¸è¦æå¨ä¿®æ¹ãç±äºä»¥ä¸çåæå·²ç¸å½å ¨é¢ï¼è¿ä¸ªæ¹æ³æ¯æææçã
2. å¨ç¼ç¨è¿ç¨ä¸å°±è¦æ¶å¸¸æ³¨ææµè¯ Release çæ¬ï¼ä»¥å æå代ç 太å¤ï¼æ¶é´åå¾ç´§ã
3. å¨ Debug çä¸ä½¿ç¨ /W4 è¦å级å«ï¼è¿æ ·å¯ä»¥ä»ç¼è¯å¨è·å¾æ大é度çé误信æ¯ï¼æ¯å¦ if( i =0 )å°±ä¼å¼èµ· /W4 è¦åãä¸è¦å¿½ç¥è¿äºè¦åï¼é常è¿æ¯ä½ ç¨åºä¸ç Bug å¼èµ·çãä½ææ¶ /W4 ä¼å¸¦æ¥å¾å¤åä½ä¿¡æ¯ï¼å¦ æªä½¿ç¨çå½æ°åæ° è¦åï¼èå¾å¤æ¶æ¯å¤çå½æ°é½ä¼å¿½ç¥æäºåæ°ãæ们å¯ä»¥ç¨:
#progma warning(disable: )
//ç¦æ¢
//...
#progma warning(default: )
//éæ°å 许æ¥ææ¶ç¦æ¢æ个è¦åï¼æ使ç¨
#progma warning(push, 3)
//设置è¦å级å«ä¸º /W3
//...
#progma warning(pop)
//é设为 /W4
æ¥ææ¶æ¹åè¦å级å«ï¼ææ¶ä½ å¯ä»¥åªå¨è®¤ä¸ºå¯ççé£ä¸é¨å代ç ä½¿ç¨ /W4ã
4. ä½ ä¹å¯ä»¥åDebugä¸æ ·è°è¯ä½ çReleaseçï¼åªè¦å å ¥è°è¯ç¬¦å·ãå¨Project/Settings... ä¸ï¼éä¸ Settings for "Win Release"ï¼éä¸ C/C++ æ ç¾ï¼Category é Generalï¼Debug Info é Program Databaseãåå¨ Link æ ç¾ Project options æåå ä¸ "/OPT:REF" (å¼å·ä¸è¦è¾)ãè¿æ ·è°è¯å¨å°±è½ä½¿ç¨ pdb æ件ä¸çè°è¯ç¬¦å·ã
ä½è°è¯æ¶ä½ ä¼åç°æç¹å¾é¾è®¾ç½®ï¼åéä¹å¾é¾æ¾å°?è¿äºé½è¢«ä¼åè¿äºãä¸è¿ä»¤äººåºå¹¸çæ¯ï¼Call Stackçªå£ä»ç¶å·¥ä½æ£å¸¸ï¼å³ä½¿å¸§æé被ä¼åï¼æ ä¿¡æ¯ï¼ç¹å«æ¯è¿åå°åï¼ä»ç¶è½æ¾å°ãè¿å¯¹å®ä½é误å¾æ帮å©ã
2024-11-23 08:48
2024-11-23 08:45
2024-11-23 08:43
2024-11-23 08:35
2024-11-23 08:08
2024-11-23 07:40
2024-11-23 06:25
2024-11-23 06:15