亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

 

一、背景

隨著公司應(yīng)用的逐漸增多,需要集中收集公司部分應(yīng)用線上運(yùn)行的一些崩潰數(shù)據(jù)和日志來(lái)進(jìn)行分析處理,在此實(shí)踐過(guò)程中了解到系統(tǒng)data/system/dropbox目錄會(huì)生成所有應(yīng)用的相關(guān)日志文件。

這個(gè)目錄是由Android系統(tǒng)服務(wù)之一DropBoxManagerService來(lái)管理,所以由此詳細(xì)閱讀了DropBoxManagerService相關(guān)的源碼,以下簡(jiǎn)稱DBMS。

DBMS可能是Android系統(tǒng)服務(wù)源碼較少的一個(gè),所以閱讀起來(lái)相對(duì)比較簡(jiǎn)單,閱讀之后發(fā)現(xiàn),其實(shí)這就是一個(gè)簡(jiǎn)易的日志文件管理服務(wù)。

我們?cè)趯?duì)應(yīng)用本地的部分日志文件進(jìn)行記錄和管理的時(shí)候,恰巧可以借鑒DBMS源碼對(duì)于文件管理的設(shè)計(jì)方案。

假設(shè)不讀源碼,如果我們自己設(shè)計(jì)日志文件管理系統(tǒng),應(yīng)該需要考慮哪些?

除了最基礎(chǔ)的獲取各類日志文件的方案,我們針對(duì)文件管理可以提出幾個(gè)需要考慮的點(diǎn):

  1. 存取日志采用何種策略
  2. 設(shè)計(jì)哪些防呆策略
  3. 是否需要對(duì)外提供接口,提供哪些接口
  4. 如何保證性能
  5. 多進(jìn)程的問(wèn)題如何解決
  6. 文件丟失該如何處理
  7. 文件變化如何通知使用方

我們帶著以上問(wèn)題來(lái)對(duì)DBMS進(jìn)行一個(gè)了解

二、DropBoxManagerService簡(jiǎn)介

DropBoxManagerService是Android系統(tǒng)的服務(wù)之一,采用C/S結(jié)構(gòu):

  • Client端:DropboxManager,用于對(duì)應(yīng)用層提供接口。
  • Server端:DropBoxManagerService,管理系統(tǒng)目錄(data/system/dropbox)的系統(tǒng)服務(wù)。
  • 系統(tǒng)Setting數(shù)據(jù)庫(kù):負(fù)責(zé)管理DBMS的一些配置信息。

整體架構(gòu)關(guān)系如下圖所示:

圖片

2.1 DropBox目錄簡(jiǎn)介

這個(gè)目錄的目錄結(jié)構(gòu)如下圖所示:

圖片

里面存放的都是系統(tǒng)的一些日志文件,針對(duì)不同類型的文件,文件名稱和后綴也有所不同。

2.1.1 文件格式

[email protected]

  • tag:代表日志類型,常見(jiàn)的tag:data_App_anr,system_app_crash,data_app_nativecrash,其中data_app表示普通應(yīng)用,system_app表示系統(tǒng)應(yīng)用
  • timeStampMillis:日志的時(shí)間戳,一般情況下等于崩潰的時(shí)間,有些情況下系統(tǒng)會(huì)做一些調(diào)整
  • extentions:后綴名,常見(jiàn)的文件后綴名:.txt,.lost,.txt.gz,.tmp,一般的日志文件都是.txt或者.txt.gz,文件被刪除后的記錄會(huì)以.lost命名

這種文件命名方式優(yōu)點(diǎn)是可以一眼看出這是什么類型的文件。

2.1.2 常見(jiàn)的文件

  1. JE文件:
    [email protected]
  2. NE文件:
    [email protected]
  3. ANR文件:
    [email protected]

還包括一些系統(tǒng)其它的錯(cuò)誤日志,內(nèi)存,重啟相關(guān)的等等。

2.2 提供的接口

2.2.1 添加文件

addData/addFile/addEntry

2.2.2 獲取文件

getNextEntry,根據(jù)tag和時(shí)間戳來(lái)獲取想要的文件。

2.2.3 dump目錄信息

獲取DropBox目錄的一些信息:文件個(gè)數(shù),文件列表,文件詳細(xì)信息等,可以通過(guò)命令行操作(dumpsys dropbox)。

$ dumpsys dropbox
Drop box contents: 131 entries
Max entries: 1000
// 以下省略......

2.2.4 其它CMD命令

提供其他一些CMD操作的命令,如set-rate-limit,add-low-priority等等。

2.3 目錄管控配置

2.3.1 默認(rèn)基礎(chǔ)配置及文件清除策略

這些配置存在系統(tǒng)的setting數(shù)據(jù)庫(kù)里面,可以通過(guò)settings.global來(lái)訪問(wèn)配置。

文件存儲(chǔ)的配置主要包括以下幾個(gè)維度:

  1. 文件存活時(shí)長(zhǎng)(默認(rèn)3天);
  2. 最大存儲(chǔ)文件數(shù)量(默認(rèn)1000個(gè));
  3. 低內(nèi)存情況下最大文件數(shù)量(默認(rèn)300個(gè));
  4. DropBox目錄所能使用的空間(默認(rèn)10MB);
  5. DropBox目錄最多占可用存儲(chǔ)(可用存儲(chǔ)=系統(tǒng)可用存儲(chǔ)-系統(tǒng)總存儲(chǔ)*預(yù)留比例)的比例(10%);
  6. DropBox使用需要預(yù)留的存儲(chǔ)占總存儲(chǔ)的比例(10%);
  7. 清除空間時(shí)掃描磁盤空間的時(shí)間間隔;
  8. 需要壓縮的最小文件大小。

根據(jù)以上配置,我們可以知道該目錄下的日志文件清除策略,觸發(fā)配置上限后會(huì)及時(shí)的刪除文件。

在以下三種情況會(huì)執(zhí)行文件清除策略,防止DropBox占用太多的空間:

  1. 設(shè)備低內(nèi)存;
  2. setting配置發(fā)生變更;
  3. 添加文件。

同時(shí)在添加文件的時(shí)候,超過(guò)配置的可占用空間,會(huì)被丟棄。

/**
 * Trims the files on disk to make sure they aren't using too much space.
 * @return the overall quota for storage (in bytes)
 */
private synchronized long trimToFit() throws IOException {
    return mCachedQuotaBlocks * mBlockSize;
}

2.3.2 文件刪除及標(biāo)記處理策略

在上述策略不滿足后,部分文件會(huì)被刪除,刪除后,會(huì)在DropBox添加一個(gè).lost的空文件標(biāo)記被刪除的文件。

2.3.3 文件類型管控

DropBoxMangerService對(duì)于可存儲(chǔ)的文件類型也有控制,主要是對(duì)于TAG的控制。

public boolean isTagEnabled(String tag) {}

2.3.4 權(quán)限管控

使用DropBox需要READ_LOGS權(quán)限和PACKAGE_USAGE_STATS兩個(gè)權(quán)限。

2.4 讀寫策略

這塊涉及到DBMS幾個(gè)關(guān)鍵方法和屬性,主要涉及到初始化(init),添加文件(addEntry),獲取文件(getNextEntry),文件類型(EntryFile)。

DBMS作為系統(tǒng)服務(wù)會(huì)由SystemServer啟動(dòng),添加文件(addEntry)和獲取文件(getNextEntry)在調(diào)用時(shí)會(huì)先進(jìn)行初始化(init)。

其中每個(gè)文件都會(huì)轉(zhuǎn)換成一個(gè)EntryFile類來(lái)管理,關(guān)系見(jiàn)下圖:

圖片

下面了解一下初始化,EntryFile,添加文件和獲取文件的具體內(nèi)容:

2.4.1 初始化

初始化會(huì)將DropBox文件列表緩存到內(nèi)存中。

/** If never run before, scans disk contents to build in-memory tracking data. */
private synchronized void init() throws IOException {
    // 省略代碼......
     File[] files = mDropBoxDir.listFiles(); // 列出所有文件
     for (File file : files) {
          EntryFile entry = new EntryFile(file, mBlockSize); // 一個(gè)日志文件對(duì)應(yīng)一個(gè)EntryFile對(duì)象
          enrollEntry(entry); // 加入到mAllFiles
    }
}

初始化的時(shí)機(jī):

  • 設(shè)備存儲(chǔ)容量低廣播回調(diào) 
  • 設(shè)置配置項(xiàng)修改
  • 添加日志文件
  • 獲取日志文件
  • dump 命令行列出DropBox的一些內(nèi)容

2.4.2 EntryFile文件屬性

每個(gè)文件對(duì)應(yīng)一個(gè)EntryFile,用block數(shù)來(lái)統(tǒng)計(jì)大小,DBMS涉及的讀寫都是根據(jù)磁盤的blockSize來(lái)進(jìn)行,效率會(huì)更高。

static final class EntryFile implements Comparable<EntryFile> {
        public final String tag; // 日志文件的tag,類型
        public final long timestampMillis; // 日志文件的時(shí)間戳
        public final int flags; // 日志文件的flag,標(biāo)志TEXT,EMPTY,GZIPPED
        public final int blocks; // 存放文件的塊數(shù)
}

2.4.3 添加文件

添加一個(gè)日志文件,常見(jiàn)的在Ams中的addErrorToDropBox方法調(diào)用。

添加文件管控策略

① .lost的文件格式不允許添加。

// 如果添加.lost的文件,拋異常
if ((flags & DropBoxManager.IS_EMPTY) != 0) throw new IllegalArgumentException();

② 配置不允許記錄的TAG,不會(huì)被添加。

// 從設(shè)置里面讀取這個(gè)tag是否被允許記錄
if (!isTagEnabled(tag)) return;

③ 根據(jù)系統(tǒng)設(shè)置的磁盤塊大小進(jìn)行寫入,提高寫入效率。

int bufferSize = mBlockSize;

④ 異常時(shí)間戳文件矯正:寫入文件前會(huì)將超過(guò)當(dāng)前時(shí)間10s的文件修改時(shí)間后重新命名并加入到緩存文件列表中。

// 找出當(dāng)前時(shí)間10s之后的所有文件
SortedSet<EntryFile> tail = mAllFiles.contents.tailSet(new EntryFile(t + 10000));
EntryFile[] future = null;
if (!tail.isEmpty()) {
    future = tail.toArray(new EntryFile[tail.size()]);
    tail.clear();  // 從文件列表中mAllFiles清除掉超過(guò)當(dāng)前時(shí)間的
}
// 省略代碼......
for (EntryFile late : future) {
    if ((late.flags & DropBoxManager.IS_EMPTY) == 0) { // 將這些超過(guò)當(dāng)前時(shí)間的文件重命名,時(shí)間戳依次+1,并且重新加入到mAllFiles中
        enrollEntry(new EntryFile());
    }
}

⑤ 添加文件的順序,先創(chuàng)建臨時(shí)文件,然后使用文件的rename方法,rename方法是原子操作,保證并發(fā)操作的安全。

// 通過(guò)rename方法保存文件,保證并發(fā)操作的安全
temp.renameTo(file))

⑥ 文件添加完成之后通過(guò)發(fā)送廣播通知,廣播分為實(shí)時(shí)廣播和延遲廣播,延遲廣播用來(lái)通知優(yōu)先級(jí)較低的文件。

//低優(yōu)先級(jí)的可以發(fā)送延時(shí)廣播
mHandler.maybeDeferBroadcast(tag, time);
//高優(yōu)先級(jí)的發(fā)送實(shí)時(shí)廣播
mHandler.sendBroadcast(tag, time);

2.4.4 獲取文件

DBMS獲取文件的邏輯比較簡(jiǎn)單,根據(jù)方法名getNextEntry(String tag, long millis,...)我們可以見(jiàn)名知意,主要根據(jù)使用者傳入的時(shí)間戳,找出這個(gè)時(shí)間戳往后的第一個(gè)文件。

for (EntryFile entry : list.contents.tailSet(new EntryFile(millis + 1))) {
         return new DropBoxManager.Entry(entry.tag, entry.timestampMillis, file, entry.flags);
}

2.5 源碼閱讀總結(jié)

2.5.1 回答我們閱讀前提出的問(wèn)題

① 存取日志的策略

  • 會(huì)在低存儲(chǔ),添加獲取文件等時(shí)機(jī)將文件列表初始化到內(nèi)存中。

② 設(shè)計(jì)哪些防呆策略

  • 提供了文件大小,存儲(chǔ)占比等限制。
  • 會(huì)在低存儲(chǔ),配置更改的時(shí)候清除文件。
  • 配置保存在setting中,然后通過(guò)ContentObserver來(lái)監(jiān)聽(tīng)配置變化。

③ 對(duì)外提供哪些接口

  • 提供添加獲取,以及cmd命令相關(guān)的接口,開發(fā)調(diào)試都能兼顧。

④ 如何保證性能

  • 從源碼的注解可以看出,目前每個(gè)Entry無(wú)論大小都對(duì)應(yīng)一個(gè)文件效率是比較低,源碼也列出了TODO,考慮用單文件隊(duì)列來(lái)優(yōu)化。
// TODO: This implementation currently uses one file per entry, which is
// inefficient for smallish entries -- consider using a single queue file
// per tag (or even globally) instead.
  • 采用文件系統(tǒng)塊大小來(lái)讀寫來(lái)提高效率。

⑤ 多進(jìn)程的問(wèn)題如何解決

  • 文件操作都是先寫temp,然后采用rename的方案來(lái)保證原子操作從而保證并發(fā)操作的安全。
  • addEntry和getNextEntry都做了加鎖處理。

⑥ 文件丟失該如何處理

  • 文件被刪除后,會(huì)用一個(gè)同名的空文件來(lái)替代,從而標(biāo)記有文件被刪除了。

⑦ 文件變化如何通知使用方

  • 通過(guò)發(fā)廣播的方式來(lái)通知外界,針對(duì)不同優(yōu)先級(jí)的文件又設(shè)置實(shí)時(shí)和延時(shí)廣播。

2.5.2 其它點(diǎn)

  1. 文件存儲(chǔ)不光限制大小,也會(huì)限制文件類型
  2. 文件不是全部壓縮的,超過(guò)一定大小的文件會(huì)進(jìn)行壓縮
  3. 文件命名有講究,包含了應(yīng)用類型,崩潰信息,發(fā)生時(shí)間等相關(guān)信息
  4. 文件獲取是根據(jù)時(shí)間戳先后來(lái)獲取的,對(duì)于時(shí)間戳異常的文件會(huì)進(jìn)行時(shí)間上的調(diào)整

2.5.3 作為使用者的看法

當(dāng)然,我在使用源碼的過(guò)程中,也發(fā)現(xiàn)我個(gè)人覺(jué)得可以優(yōu)化的點(diǎn)。

  1. 在使用中,部分文件命名應(yīng)該加上包名,類似應(yīng)用產(chǎn)生的崩潰文件,可以按包名區(qū)分文件,對(duì)使用更友好,當(dāng)然這個(gè)設(shè)計(jì)的初衷是給系統(tǒng)統(tǒng)一使用,可能不對(duì)外開放。
  2. 權(quán)限管控過(guò)于單一,對(duì)于業(yè)務(wù)本身的一些異常日志,應(yīng)當(dāng)支持自由查看。
  3. 這些文件的信息應(yīng)該用數(shù)據(jù)庫(kù)維護(hù)起來(lái)更好,方便使用者用,當(dāng)然可能設(shè)計(jì)可能會(huì)變得更復(fù)雜,不夠簡(jiǎn)約。

三、源碼閱讀應(yīng)用–日志文件管理&上報(bào)設(shè)計(jì)

3.1 概述

背景:

部分應(yīng)用希望上報(bào)應(yīng)用運(yùn)行時(shí)的一些日志,包括運(yùn)行時(shí)log,崩潰log,Hprof內(nèi)存快照,捕獲異常等等

需求:

需要設(shè)計(jì)一套客戶端的日志文件收集、管理及上報(bào)一個(gè)功能

參考:

  1. 日志保存管理方案可以參考DBMS中的一些策略
  2. 日志上傳方案參考業(yè)內(nèi)已有的一些優(yōu)秀模型

3.2 方案

整體方案方案采用生產(chǎn)者-消費(fèi)者模型,其中幾個(gè)關(guān)鍵節(jié)點(diǎn)

  1. 生產(chǎn)者:應(yīng)用的多個(gè)進(jìn)程,他們可能會(huì)生成不同類型的日志,并寫入到指定的文件目錄
  2. 臨時(shí)文件目錄:根據(jù)文件類型、優(yōu)先級(jí)設(shè)置不同目錄來(lái)存放臨時(shí)文件
  3. 上報(bào)數(shù)據(jù)目錄:臨時(shí)文件目錄中的文件會(huì)通過(guò)rename方案寫到上報(bào)數(shù)據(jù)目錄
  4. 消費(fèi)者:上報(bào)進(jìn)程,上報(bào)進(jìn)程會(huì)通過(guò)FileObserver監(jiān)聽(tīng)變化,從而來(lái)上報(bào)文件

整體的流程圖如下:

圖片

3.3 確定對(duì)外接口

  1. 獲取文件的接口
  2. 存文件的接口
  3. 統(tǒng)計(jì)文件(類型,數(shù)量)的接口
  4. 更改部分配置策略的接口
  5. 主動(dòng)上報(bào)的接口
  6. 其它自定義參數(shù)的接口

3.4 確定收集管控策略

  1. 是否允許收集:該配置關(guān)閉后,本地不會(huì)執(zhí)行任何收集行為
  2. 日志存儲(chǔ)目錄:私有目錄固化出一個(gè)空間
  3. 文件命名方式:參照DBMS,進(jìn)程名_日志類型_前后臺(tái)@時(shí)間戳.txt.gz
  4. 日志類型開關(guān):每個(gè)日志類型設(shè)置是否允許手機(jī)
  5. 收集日志類型:崩潰日志,運(yùn)行時(shí)日志,內(nèi)存快照,捕獲日志,其它自定義日志等
  6. 日志存活時(shí)長(zhǎng):參照DBMS,超過(guò)一定時(shí)間,則刪除文件
  7. 日志存儲(chǔ)空間:參照DBMS,設(shè)置一個(gè)手機(jī)可用存儲(chǔ)的比例·
  8. 日志文件數(shù)量:超過(guò)指定數(shù)量,則刪除部分文件;參照DBMS,當(dāng)可用存儲(chǔ)較低的情況,應(yīng)該存儲(chǔ)更少的文件數(shù)量
  9. 其余初始化的一些時(shí)機(jī),同樣參考DBMS

3.5 確定上報(bào)管控策略

  1. 是否允許上報(bào),該配置關(guān)閉后,不允許上報(bào)行為
  2. 是否允許在流量情況下上報(bào),該配置設(shè)置不允許后,只允許在wifi情況下上報(bào)
  3. 流量情況下單次、單日、單月最多可上報(bào)的文件大小,該配置控制流量情況下,應(yīng)用在上報(bào)時(shí)可以上報(bào)的文件大小
  4. wifi情況下單次、單日、單月最多可上報(bào)的文件大小,該配置控制wifi情況下,應(yīng)用在上報(bào)時(shí)可以上報(bào)的文件大小
  5. 上報(bào)間隔時(shí)間,該配置控制低優(yōu)先級(jí)的文件上報(bào)時(shí)間間隔
  6. 上報(bào)失敗次數(shù)限制,該配置控制在失敗一定次數(shù)以后,不再允許上報(bào)
  7. 上報(bào)優(yōu)先級(jí)(低優(yōu)先級(jí)的日志無(wú)需頻繁上報(bào))
  8. 弱網(wǎng)絡(luò)情況本次上報(bào)的文件大小
  9. 單次、單日、單月允許使用的流量大小,該配置控制應(yīng)用在上報(bào)時(shí)可以使用的流量大小
  10. 可上報(bào)的最低電量限制,該配置控制上報(bào)情況下最小電量限制

3.6 收集日志方案

  • DropBox日志:先讀取到本地,然后存儲(chǔ)上報(bào)
  • 運(yùn)行時(shí)日志:利用adb logcat命令輸出日志到本地儲(chǔ)存上
  • 內(nèi)存快照:dump Hprof文件,然后進(jìn)行一些裁剪,以便于能夠以更小的體積上傳
  • 其它日志:實(shí)時(shí)輸出記錄到本地,按需上報(bào)

以上具體方案不作為本次重點(diǎn),不再詳述。

3.7 寫入日志方案

圖片

通過(guò)網(wǎng)絡(luò)課程的學(xué)習(xí),了解到mmap的性能非常高,所以最終采用“多進(jìn)程寫+mmap”的方案,并且避免了跨進(jìn)程的調(diào)用堆積,效率很高

3.8 上報(bào)日志方案

參照DBMS添加文件的實(shí)時(shí)和延時(shí)通知方案,上報(bào)也分為實(shí)時(shí)上報(bào)和延時(shí)上報(bào)

  • 實(shí)時(shí)上報(bào):出現(xiàn)一份日志,就直接上報(bào),針對(duì)重要性較高的日志
  • 延時(shí)上報(bào):達(dá)到一定數(shù)量,或者達(dá)到一定時(shí)間進(jìn)行上報(bào)

圖片

3.9 數(shù)據(jù)監(jiān)控

3.9.1 質(zhì)量監(jiān)控

圖片

 

3.9.2 容災(zāi)監(jiān)控

圖片

 

四、總結(jié)

本文主要講了兩塊內(nèi)容:

1、DropBoxManagerService源碼閱讀與解析,包括接口設(shè)計(jì)、文件存儲(chǔ)的管控機(jī)制和策略,多進(jìn)程的處理,異常防呆機(jī)制

2、應(yīng)用日志收集與上報(bào)方案,主要參考DropBoxManagerService源碼的設(shè)計(jì)

我們經(jīng)常強(qiáng)調(diào)源碼閱讀,源碼究竟能給我們帶來(lái)什么呢?我認(rèn)為主要有以下幾點(diǎn):

  • 編碼技術(shù)的提升
  • 分析問(wèn)題的思路
  • 解決方案的設(shè)計(jì)
  • 設(shè)計(jì)模式的應(yīng)用

本文拋磚引玉,借助以上案例簡(jiǎn)單地講了一下DBMS源碼以及源碼閱讀的應(yīng)用,希望在源碼閱讀方面能夠帶給大家一些啟發(fā),同時(shí)對(duì)Android系統(tǒng)一些不常見(jiàn)的服務(wù)有一個(gè)了解。

分享到:
標(biāo)簽:Android
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定