以為又係Bug(因為現時0.1版本一卡多號會有這個問題)。
查返log原來真係打入三次,重係前後15秒內。究竟係佢無sort duplicate,定係故意要使攔截陌生來電、但不攔截數分鐘內第二次同一來電的人接聽?係唔係要加個一分鐘內連續4次不在通訊錄號瑪,先俾佢接入的功能?
另外快將推出的黑白名單預覽。
以為又係Bug(因為現時0.1版本一卡多號會有這個問題)。
查返log原來真係打入三次,重係前後15秒內。究竟係佢無sort duplicate,定係故意要使攔截陌生來電、但不攔截數分鐘內第二次同一來電的人接聽?係唔係要加個一分鐘內連續4次不在通訊錄號瑪,先俾佢接入的功能?
另外快將推出的黑白名單預覽。
開發版0.2.0(終於)加入了名單功能,自訂我的黑名單及白名單(可自vCard及舊版小熊匯出的txt匯入),以及自訂不作攔截的例外廣告電話/名稱名單,例如指定不攔截某機構。此外亦預設自動將已回報黑名單新電話加入臨時名單,即時開始攔截。
現有來電紀錄加入了刪除功能。
暫未有匯出名單功能,遲些會加入(計劃採用標準vCard 2.1 format,方便交換)。
遲些亦會加入可於不明來電後,自動彈出回報電話的選項。
其他改動包括
推出0.2版後,更新一下與小熊新舊版的(扮客觀的)比較,如不打算使用小熊付費新版的話,可參考一下。
頭盔﹕不保證準確,有錯請指。
注意﹕根據HKJunkCall公布,2016年3月HKJunkCall提升保安,小熊舊版預計將不能再更新資料庫。
舊版小熊用戶若希望可將黑白名單匯入小鴨幹線,亦想更新至小熊5新版,請在更新小熊前匯出名單,因為小熊5的匯出格式似乎已加密,其他App不可能匯入。
功能/特點 | 小鴨幹線 0.2.X | 小熊來電 4.42 | 小熊來電 5.0.5(非付費版) |
---|---|---|---|
一般 | |||
廣告(佔用畫面,記憶及數據用量) | 沒有 | 有(一次性付費可移除) | 有(按月付費可移除) |
付費方可使用的選項及資料,佔用畫面,記憶及數據用量 | 沒有 | 沒有(付費僅移除廣告) | 有 |
使用可連同其他App紀錄,追蹤或提交用戶手機資料、使用習慣的analytics/ad/tracking網絡 | 沒有 | Admob (1) | Admob Tapjoy Flurry Analytics ThreatMetrix SDK (1) |
香港製造 | 是 | 是 | ?? |
攔截方式 | |||
掛斷 | 有 | 有 | 有 |
靜音 | 有 | 有(但Android5或以上若震動為開,攔截來電時不會停止) | 有(但Android5或以上若震動為開,攔截來電時不會停止) |
接通再掛斷 | 有 | 有(但Android5或以上只限root) | 沒有 |
沒有動作 | 有 | 有 | 有 |
通話時攔截 | 有(只限root及部份機種) | 有(只限root及部份機種) | 沒有 |
資料庫 | |||
攔截資料來源 | HKJunkcall (在香港義務運作多年,管理員人手核實,以減少惡意回報或錯誤資料導致錯誤攔截的機會) | HKJunkcall | HKJunkcall, Whoscall, MalCallDB(不清楚後兩者香港有否人核實,或純靠運算) |
HKJunkcall資料庫查閱 | 詳細資料 | 詳細資料 | 部份資料 |
自動更新 | 自動更新,可選每天檢查四次(通常每天更新1-2次)至每2星期一次,可指定時間,可限Wifi或非漫游數據 | 自動更新最多每天一次至每月一次,可指定時間,不可指定限Wifi | 自動更新僅可每天一次,不可指定時間,可限Wifi |
GCM推送 | 無 | 有(發放推廣訊息及通知,及極速攔截清單) | 有(發放推廣訊息及通知) |
即時推送更新 | 無 | 有(極速攔截清單) | 無(即時惡意名單,限月費用戶,或限時推廣期間) |
手動更新 | 有更新時可立刻下載 | 有更新時可立刻下載 | 僅可每天下載一次 |
Whoscall來電辨識(來電資料會提交Server,或會被記錄) | 沒有 | 有(可關閉) | 有(可關閉) |
攔截條件選項 | |||
HKJunkcall選項 | 行業 | 行業,層級(0-4),分類 | 行業,層級(簡化為高中低),分類 |
攔截匿名(無顯示)來電 | 有 | 有 | 有 |
容許第二次匿名來電 | 有(可選1,2,3或5分鐘) | 有(2分鐘) | 有(2分鐘) |
指定時間攔截匿名來電 | 沒有(0.3版會加入可達相同效果的自訂模式功能) | 有 | 有 |
攔截後的匿名來電也攔截 | 有(可選1,2,3或5分鐘) | 有(2分鐘) | 沒有 |
不攔截(忽略)聯絡人 | 有 | 有 | 有 |
攔截所有電話 | 有 | 有 | 有 |
指定時間攔截所有電話 | 沒有(0.3版會加入可達相同效果的自訂模式功能) | 有 | 沒有(可指定時間的勿擾模式限月費用戶) |
設定漫游時攔截所有電話 | 沒有(須手動設定攔截所有電話)(0.3版會加入可達相同效果的自訂模式功能) | 有 | 有 |
攔截所有電話/容許聯絡人時,可容許非聯絡人第二次來電 | 有(可選1,2,3或5分鐘) | 沒有 | 沒有 |
自訂名單 | 私人黑名單,私人白名單(兩者皆可指定限於漫遊或非漫遊使用),例外廣告電話,例外廣告名稱(類似符合名稱白名單),臨時廣告(回報時自動加入) | 黑名單,白名單,漫遊白名單,符合名稱白名單 | 黑名單,白名單,漫遊白名單 |
名單匯入匯出 | 可從標準vCard(Android,Google Contacts及iPhone可匯出的.vcf格式)及小熊4匯出的txt格式,匯入黑名單及白名單(漫遊/非漫遊) (稍後將加入匯出標準vCard的功能) | 可將黑白名單及漫遊白名單,以自定義的txt格式匯出及匯入 | 可將黑白名單及漫遊白名單,以自訂的binary格式匯出及匯入(格式應經加密處理,其他App已不能讀取) |
攔截無效IDD | 有 | 沒有 | 沒有 |
顯示IDD來源地以助辨識是否偽冒 | 有 | 沒有 | 沒有 |
其他功能/特點 | |||
回報 | 有(用戶先行開啟App)(稍後將會加入可設定為來電後自動彈出) | 有(可選擇不明來電後彈出視窗) | 有(可選擇不明來電後彈出視窗) |
移除通話紀錄 | 有 | 有 | 有 |
紀錄雙卡機來電SIM卡 | 有(部份機種) | 沒有 | 沒有 |
翻轉手機進行過濾/靜音 | 沒有 | 有 | 有 |
RAM用量 (Android 6安裝後更新,攔截,再關閉界面之後(2)) | 7.0M (running) 29M (cached) | 43M (running) | 58M (running) |
攔截後彈出要求給五星的視窗 | 沒有 | 沒有 | 有(據報會直至給星後) |
彈出推廣活動視窗 | 沒有 | 沒有 | 有(據報最近有恭喜發財推廣即時惡意電話視窗) |
在HKJunkCall 2016年3月提升保安後可繼續運作 | 可 | 不可 | 可 |
權限 | 小鴨幹線 0.2.X | 小熊來電 5 |
---|---|---|
應用程式內購買 | 需要 | |
裝置和應用程式記錄 | ||
擷取執行中的應用程式 | 需要 | 需要 |
身分識別 | ||
找出裝置上的帳戶 | 需要 | |
通訊錄 | ||
找出裝置上的帳戶 | 需要 | |
讀取您的通訊錄 | 需要 | 需要 |
修改您的通訊錄 | 需要 | 需要 |
短訊 | ||
接收文字訊息 (MMS) | 需要 | |
接收文字訊息 (SMS) | 需要 | |
傳送 SMS 短訊 | 需要 | |
手機 | ||
直接撥打電話號碼 | 需要 | 需要 |
讀取手機狀態和識別碼 | 需要 | 需要 |
寫入通話記錄 | 需要 | 需要 |
讀取通話記錄 | 需要 | 需要 |
修改手機狀態 | 需要 | |
相片/媒體/檔案 | ||
修改或刪除您 USB 儲存空間中的內容 | 需要 | 需要 |
讀取 USB 儲存裝置的內容 | 需要 | 需要 |
儲存空間 | ||
修改或刪除您 USB 儲存空間中的內容 | 需要 | 需要 |
讀取 USB 儲存裝置的內容 | 需要 | 需要 |
Wi-Fi 連線資訊 | ||
Wi-Fi 連線資訊 | 需要 | |
裝置識別碼和通話資訊 | ||
讀取手機狀態和識別碼 | 需要 | 需要 |
其他 | ||
繫結至通知偵聽器服務 | 需要 | |
啟動時執行 | 需要 | 需要 |
接收互聯網資料 | 需要 | |
控制震動 | 需要 | |
停用屏幕上鎖 | 需要 | 需要 |
修改系統設定 | 需要 | 需要 |
覆蓋其他應用程式 | 需要 | 需要 |
控制近距離無線通訊 | 需要 | |
更改音效設定 | 需要 | |
防止裝置進入休眠狀態 | 需要 | 需要 |
查看網絡連線 | 需要 | 需要 |
全面網絡存取權 | 需要 | 需要 |
開發版0.2.1修正了設定為每日一次自動更新時,出現不斷重複檢查的問題,以及配合HKJunkcall保安升級。
俗語有云,there are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
出現重複檢查原因是,設定為每N天更新一次時,例如設更新時間為5:30AM,在每次檢查/更新後,會將下次檢查時間設為現在起第N次出現5:30AM的時刻,但若是次更新/檢查是在當天5:30AM前少許被觸發,上述計算便會出現 off-by-one error (所設定的時刻在N-1日後),而若N為1,則會即時觸發再檢查,直至到達指定時刻。(變相DDoS HKJunkCall server )
由於0.2.0版起,背景檢查時都會發出on-going notification(其實主要因為對應Android 6的App Standby),所以才令問題被察覺。
謝謝hkepc wiisme,093236及ahuo回報問題。現已將計算方法改為現在時刻加N日後,最接近的5:30AM。
此外,此版本配合HKJunkCall.com網站對下載資料庫檔案作出安全升級,作了相應更新,0.2.0及之前版本於三月之後,將不能再更新資料,請升級至本版本。參考:HKJunkCall公布。
此為Bug fix 版本,臨時修正0.2.1版似乎在Android4.4或以下會出現,更新失敗的問題。
更新失敗是因為在使用新的https方法匯入後,在解壓縮zip file並將內容stream到XML parser時,在(似乎限於Android 4.4 或以下(?))中的XML parser會於中途某一record彈出“no element found“錯誤,原因正在研究。
0.2.2版先解壓縮整個zip file放在buffer之後再做XML parsing,避開問題。(?)
此版同時增加了接聽再掛線時,接聽後的等侯時間,以作測試,避免一部份電話來不及完成接聽便因time out而被直接掛線。
[Edit:更新失敗原因見此篇]
On 12 February 2016, beginning from around 1440, there were reports that the Headuck Call Blocker App (hereafter “the App") failed to download the updated database from HKJunkCall.com (released at around 1340), while other apps could do so normally. Having just upgraded the App to use https (TLS) instead of http for downloading, and with some security features to prevent communication over wiretapped channels, the new code came into mind as a primary suspect for the failure.
It turned out that the problem was instead in the seemingly benign piping of simple byte stream between different standard libraries in Android.
Some basics – the InputStream class of Java is a base class representing an input stream of bytes. A number of libraries in Java supports / builds around the InputStream
class, making it a common “protocol" for chaining byte processing in Java.
The App downloads a frequently updated list of junk call numbers, provided by HKJunkCall.com in a compressed (zipped) XML format. To get the contents, it needs to decompress (unzip) the downloaded file and then parse the XML. Instead of downloading and storing the zip file on the file system, extracting it as an XML file, and then feeding the file to an XML parser, the App uses the approach of streaming the downloaded data through the necessary processing steps, which avoids the need to manage intermediate files or hold large buffers.
In Android, the standard library for decompressing a file in the zip format is java.util.zip.ZipInputStream
. It inherits from InputStream
, takes a compressed stream as input, and provides the decompressed file as an InputStream
.
For XML parsing using an event model, the standard library is javax.xml.parsers.SAXParser
. It returns an SAX interface to the XML parser (org.apache.harmony.xml.ExpatParser
in this case), and provides methods to parse files from an XML input source / stream.
Naturally, it should be simple and straightforward to feed the downloaded zip data into the ZipInputStream
class, and then feed that stream into the XML Parser. The XML parser should then happily parse the XML contents extracted from the zip file (provided of course that the XML is valid and with the right encoding).
This was implemented in the App, and indeed worked MOST of the time (ever since, and even before, the release of the App), until things go wrong.
The problem lies in fine details of how the seemingly simple method, read(byte[] b)
(and its cousins) of InputStream
, is implemented by its sub-classes, notably ZipInputStream
.
The read
method is a simple and standard one. It is used to read a byte stream into the provided buffer, b
. According to the official documentation of the base class, it –
Reads some number of bytes from the input stream and stores them into the buffer array
b
. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.If the length of
b
is zero, then no bytes are read and0
is returned; otherwise, there is an attempt to read at least one byte. If no byte is available because the stream is at the end of the file, the value-1
is returned; otherwise, at least one byte is read and stored intob
.
From the description, it is clear that, unless the length of the buffer array is 0, read(byte[])
should return either -1 (indicating the end of input), or the number of bytes read which should be >= 1, and never 0. If no byte is read but the end of stream has not been reached, the method should block, instead of returning 0.
Unfortunately, the ZipInputStream
in Android does not seem to follow the semantics strictly. Here is an extract of its read
method (Copyright 2005-2008 The Android Open Source Project under Apache 2.0)
if (inf.needsInput()) {
fill();
if (len > 0) {
entryIn += len;
}
}
int read;
try {
read = inf.inflate(buffer, start, length);
} catch (DataFormatException e) {
throw new ZipException(e.getMessage());
}
if (read == 0 && inf.finished()) {
return -1;
}
crc.update(buffer, start, read);
return read;
inf
is a variable of the Inflater
class, a wrapper of a native function to decompress the zip file. From the extract alone, it seems probable that, when read == 0
is returned from inf.inflate()
, inf.finished()
could possibly be false, and the return could be 0
.
This indeed happened – the zip file for the update on 12 February, when fetched via https and fed into the ZipInputStream
class as input, and in certain versions of Android (2.2 and 4.4, but not 5.0), caused 0 to be returned by the read
function in the middle of decompression of the XML stream, well before the end of the stream was reached.
This might be a problem originating from the ZipInputStream
class itself, or was due to the behaviour of the underlying input stream (e.g. output from decryption of https stream), with ZipInputStream
propagating the (unexpected) problem upwards without dealing with it. I did not further delve into the source to see why, since I had to handle this output either way.
Deviation from the semantics might not be a problem in itself, if the consumer of the stream were tolerant enough. In fact, in a number of common implementations for consumers of input streams, returns with zero length from read
are effectively ignored (for example, by appending nothing to a buffer, and read again). This seems to be the case too for the XML parser in ExpatParser.java
which the ZipInputStream
in the present case is ultimately fed into: (Copyright (C) 2007 The Android Open Source Project, Apache 2.0)
/**
* Parses XML from the given input stream.
*/
private void parseFragment(InputStream in)
throws IOException, SAXException {
byte[] buffer = new byte[BUFFER_SIZE];
int length;
while ((length = in.read(buffer)) != -1) {
try {
appendBytes(this.pointer, buffer, 0, length);
} catch (ExpatException e) {
throw new ParseException(e.getMessage(), this.locator);
}
}
}
However, unfortunately for this case, the input stream was fed into the parser in a slight convoluted manner. A standard Java class java.io.InputStreamReader
was used first to wrap the ZipInputStream
, and the reader itself was wrapped in an InputSource
class, which also encapsulated other information such as encoding, before feeding to the SAX parser interface. Thus, the stream passed through InputStreamReader
‘s read()
method. Given the above semantics of InputStream
‘s read
, this intervening method turned the 0
return of ZipInputStream
‘s read
into -1
(which signals the end of the stream), before feeding it into the parser.
The behaviour is evident just by looking at the return statement of InputStreamReader
‘s read
method, used when the buffer length is greater than 0 (note that this code will never return 0):
return out.position() - offset == 0 ? -1 : out.position() - offset;
As a result, to the XML parser, the input stream would appear to have reached its end at the juncture when ZipInputStream
‘s read emitted a 0 return, (less than) half way in parsing the XML file in this instance. It happened that the truncation occurred just after starting an XML tag, and the following ParseException
was thrown by the parser.
org.apache.harmony.xml.ExpatParser$ParseException: At line X, column Y: no element found
It was somewhat lucky that, in this case, the behaviour was reproducible in reruns (perhaps due to the same fragmentation of the input zip stream after decryption operation, enabling the 0 return of the ZipInputStream
to be reproduced). This allowed tracking down of the error.
Before this was completely tracked down, I found that the problem could be worked around by simply buffering the whole decompressed XML file in a BufferedInputStream
(i.e. by calling mark()
with a limit larger than the decompressed file size at the beginning, reading the whole stream until end, and then reset()
it, before feeding the stream to the parser). In retrospect, this was because the buffering of the ZipInputStream
by BufferedInputStream
(which did not involve the InputStreamReader
in-between) was tolerant of 0-byte reads, and the subsequent re-play of the stream to feed through InputStreamReader
into the parser no longer produced 0-byte reads.
BufferedReader reader1 = new BufferedReader(reader);
reader1.mark(3000000);
while ((line = reader1.readLine ()) != null) {
}
reader1.reset();
xmlReader.parse(new InputSource(reader1));
This ugly approach (hardcoded size limit and bad efficiency) was used as a stop-gap patch to fix the problem, and was release at around 1750, 3 hours after the initial report, in the urgent bug-fix version (0.2.2) of the App.
Knowing deeper about the problem, it was fixed by something similar to subclassing the ZipInputStream
class and overriding its read
methods, e.g.
@Override
public final int read(byte[] b) {
int ret;
do {
ret = super.read(b);
} while ((ret == 0) && (b.length > 0));
return ret;
}
This rectifies the semantics of ZipInputStream
‘s read
function, i.e. that read()
would not return 0, unless the buffer is of zero length, allowing the InputStream
to be handled by other routine Java libraries without problems. (This is not the actual fix used, which involves modifying an intervening thin layer of FilterInputStream
to the same effect.)
Another fix, which could also avoid the problem when used alone, is to bypass the InputStreamReader
/ InputSource
classes in between, and directly feed the byte stream to the parser, i.e. instead of
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setContentHandler(handler);
xmlReader.parse(new InputSource(new InputStreamReader(is, "UTF-8")))
use
saxParser.parse(is, handler)
and let the parser deal with the encoding (good luck). This should obviously be more efficient too. So both fixes are applied in the new version.
The problem is not unique to ZipInputStream
(or perhaps its underlying input stream). It seems that a number of other standard libraries in Java is implemented inconsistently in this aspect. See the answers here. So if one has to pass an (unknown) input stream to a reader class or other consumers which are not tolerant of zero-length reads, either make sure that the read
method of the input stream would not return 0 for non-zero-length buffers (which would mean studying its source in most cases, unless explicitly documented), or subclass it similarly to make sure that the semantics are followed.
再來一個Bug fix 版本,是0.2.1版更新失敗的問題的最後修正,見此篇。其他修改包括
此版本:
此版本亦使用了Google最新的Support Library版本(23.2.1),主要是在舊機種支援向量格式的圖像(Vector Drawable),免除為不同resolution製作不同的png檔,較為省記憶,其中主頁小鴨已轉用了vector,其他圖像亦會逐步轉用。
另一方面新版library在Android 2.X中的部份畫面出現顯示問題,AppBar捲動後畫面沒有更新(好像之前沒有人在Stackoverflow / google 回報,所以報告左),故暫時將新版App限於API 11或以上,直至library的問題解決。API 8-10(Android 2.X)可繼續使用0.2.3版。
(3月21日 更新:已找到臨時方法,override AppBarLayout.Behavior
以避開問題,下版(0.2.5版)會恢復對API 8+支援)
為慶祝北海道新幹線326開業,此版本:
以上兼容性選項,若使用上沒有問題,便不用調較;
目前未正式支援Android N,因此開啟分割畫面會出警告,不過應沒有重大問題。預計日後Android N會正式加入夜間模式,到時App內的夜間模式切換將可與系統掛勾。
更新:由於此版本在某些情况(Activity在背景被停止後再度被創立,通常在記憶不足或中止界面一段時間重啟)出現閃退問題,已暫時停止推出,直至問題解決。但已更新的用戶不會返回前一版本。有關問題影響界面但不會影響攔截。
由於小鴨幹線中的功能,介面設計及用詞均與小熊來電舊版有所不同,近日亦有用戶以小鴨代替小熊舊版後,找不到所要功能,因此下表列出對應功能的介面,以供參考:
此表是為方便替代舊版小熊來電的用戶,查閱功能設置方法,因此大致按舊版小熊來電的「偏好設定」中的介面排列。僅於小鴨幹線有的功能,不在此表列出。功能 | 收購前的舊版小熊(完整模式介面) | 小鴨幹線 0.2.5及以後 |
---|---|---|
以廣告電話嚴重性攔截 | 過濾條件>篩選層級 | 不支援 |
以廣告電話行業攔截 | 過濾條件>篩選分類 | 設定>篩選條件>(攔截以下來電)廣告電話類別 |
攔截無來電顯示號碼 | 過濾條件>過濾無顯示來電 | 設定>篩選條件>(攔截以下來電)匿名來電者 |
不攔截第二次無來電顯示號碼 | 過濾條件>允許第二次的無顯示來電 | 設定>篩選條件>(以下來電除外)匿名來電者重覆來電 |
只於指定時間攔截無來電顯示號碼 | 過濾條件>只在指定時間過濾無顯示來電 | 目前不支援,計劃0.3版加入可達致類似效果的功能 |
攔截廣告電話後的無來電顯示號碼 | 過濾條件>攔截廣告電話後的無來電顯示號碼 | 設定>篩選條件>(攔截以下來電)攔截來電後的匿名來電者 |
不攔截通訊錄上的電話 | 過濾條件>忽略連絡人號碼 | 設定>篩選條件>(以下來電除外)我的通訊錄 |
翻轉手機時攔截/靜音 | 過濾條件>翻轉手機時進行過濾/初始啟用翻轉過濾/翻轉手機時靜音 | 不支援 |
攔截短訊 | 過濾條件>過濾短訊(限Android 4.4以前的版本) | 不支援 |
攔截全部來電 | 過濾條件>全部封鎖 | 設定>篩選條件>(攔截以下來電)所有來電 |
攔截全部來電但容許通訊錄上的電話來電 | 過濾條件>全部封鎖 及 過濾條件>不過濾電話簿連絡人 | 設定>篩選條件>(攔截以下來電)不在通訊錄的來電者 |
只在指定時間全部封鎖 | 過濾條件>只在指定時間全部封鎖 | 目前不支援,計劃0.3版加入可達致類似效果的功能 |
只在漫遊時全部封鎖 | 過濾條件>全部封鎖(漫遊模式) | 目前不支援,計劃0.3版加入可達致類似效果的功能 |
非漫遊攔截動作 | 過濾動作>一般過濾動作 | 設定>攔截動作>非漫遊標準方式 (若使用root方式請同時啟用攔截動作>可使用root方式) |
漫遊攔截動作 | 過濾動作>漫遊過濾動作 | 設定>攔截動作>漫遊標準方式 (若使用root方式請同時啟用攔截動作>可使用root方式) |
通話時仍攔截廣告電話(root功能) | 過濾動作>通話時收到廣告電話時拒絕 | 設定>攔截動作>通話時仍攔截來電 (須先啟用攔截動作>可使用root方式) |
廣告電話時僅通知而沒有動作 | 過濾動作>對封鎖清單的項目不進行動作 | 沒有對應選項,可於設定>攔截動作>非漫遊/漫遊標準方式中,整體設定攔截來電的動作 |
提示訊息顯示時間設定 | 過濾動作>提示訊息至少顯示長度 | 沒有對應選項,訊息會顯示至掛線後數秒 |
刪除已攔截電話的系統的來電紀錄 | 過濾動作>刪除來電紀錄項目 | 設定>攔截動作>刪除系統來電紀錄 |
攔截後強制解除靜音 | 過濾動作>過濾後強制解除靜音狀態 | 設定>程式選項>攔截後強制取消靜音 |
攔截後通知 | 過濾動作>顯示列頂通知 | 設定>攔截動作>攔截後發出通知 |
不顯示接聽後提示 | 過濾動作>不顯示接聽後提示 | 目前不支援接聽後提示,稍後會加入 |
自訂私人黑名單 | 自訂清單>黑名單 | 我的名單>黑名單 (請啟用 設定>篩選條件>我的黑名單,已預設啟用) |
自訂私人白名單 | 自訂清單>白名單 | 我的名單>白名單>編輯白名單項目時指定漫遊和非漫遊(預設) (請啟用 設定>篩選條件>我的白名單) |
自訂不攔截的廣告電話名單(查看名單) | 自訂清單>白名單(註:小熊並無區分此項與非廣告的白名單) | 廣告名單>例外電話 |
自訂不攔截的廣告電話名單(加入名單) | 搜尋>長按項目>加到白名單 | 廣告名單>單擊項目>加入例外電話名單 |
自訂漫遊時的私人白名單 | 過濾條件>自訂清單>白名單(漫遊專用) 並啟用過濾條件>使用漫遊模式白名單 | 我的名單>白名單>編輯白名單項目時指定僅限漫遊 (請啟用 設定>篩選條件>我的白名單,已預設啟用) |
以廣告電話名稱攔截(查看名單) | 過濾條件>自訂清單>完全符合名稱的白名單 | 廣告名單>例外名稱 |
以廣告電話名稱攔截(加入名單) | 搜尋>長按項目>加到符合名稱白名單 | 廣告名單>單擊項目>加入例外名稱名單 |
HKJunkCall白名單(公共機構資料) | 資料庫選項>已知來電資料 | 不支援 |
資料庫存於SD卡 | 資料庫選項>將資料庫儲存至SD卡 | 不支援 |
手動更新資料庫 | 資料庫選項>從網際網絡更新資料庫 | 總覽>廣告電話(香港)>立即更新資料庫(註:只會於有更新時顯示) |
強制更新資料庫 | 資料庫選項>強制更新資料庫 | 沒有對應功能(正常應沒有作用) |
從內建清單更新資料庫 | 資料庫選項>從內建清單更新資料庫 | 沒有對應功能(App已不附帶內建清單) |
更新後發出通知 | 資料庫選項>成功更新時通知 | 總覽>廣告電話(香港)>資料庫更新設定>網絡更新後發出通知 |
設定使用自動更新 | 資料庫選項>自動更新設定>(選擇推送或按時更新) | 總覽>廣告電話(香港)>啟用背景數據/啟用自動更新 |
網上推送更新 | 資料庫選項>自動更新設定>以網上推送 | 不支援 |
極速攔截清單 | 資料庫選項>自動更新設定>極速攔截清單 | 不支援 |
自動回報已攔截來電 | 資料庫選項>回報選項>回報已篩選來電 | 設定>攔截動作>自動回報已攔截廣告電話 |
設定只在更新資料庫時才回報已攔截來電 | 資料庫選項>回報選項>離線回報已篩選來電 | 沒有對應功能(若想省流量可使用 總覽>廣告電話(香港)>背景數據限制) |
設定只在更新資料庫時才回報新電話 | 資料庫選項>回報選項>離線回報新電話 | 沒有對應功能(若想省流量可使用 總覽>廣告電話(香港)>背景數據限制) |
設定來電掛斷延遲 | 資料庫選項>進階/除錯選項>延遲掛斷來電 | 設定>程式選項>掛斷動作延時 |
等候電話介面 | 資料庫選項>進階/除錯選項>等候電話介面 | 設定>程式選項>接通前跳過等候電話進程(註:只於Android4.4或以下,接通再掛斷時生效) |
掛線前不靜音 | 資料庫選項>進階/除錯選項>不要在掛線前靜音 | 沒有對應功能,但若有其他軟件干擾以致攔截後變為靜音,可使用設定>程式選項>攔截後強制取消靜音 |
強制停用IDD前置檢查 | 資料庫選項>進階/除錯選項>強制停用IDD前置檢查 | 沒有對應功能 |
介面語言 | Language | 設定>程式選項>語言 |
此外,若希望可將小熊來電舊版自訂黑白名單匯入小鴨幹線,亦想嘗試小熊來電新版,請在更新小熊前匯出自訂名單,再匯入小鴨幹線,因為新版小熊的匯出格式已加密,其他App不能匯入,因此更新小熊後轉用其他App,只能自行再重新輸入名單。
按5月27日的裝了小鴨的手機,Android版本佔有率的排名,Android 6終於升至第一位,佔27.49%,追過了第2位的Android 5.0 (27.40%)。第3位為Android 5.1 (22.32%),而第4位為Android 4.4 (14.01%)。
在3個月前,6.0的用戶還是10%未滿的,比4.4還少,排名第4,之後應是由於各主要型號手機的棉花糖update相繼推出,6.0的用戶迅速增長,佔有百份率在3個月內急增3倍。
另一方面,在Google的Android全球市佔dashboard中(截至5月2日),這4個版本的位置剛好倒轉,而且Android 6.0百份比仍未超越4.2,只有個位數。頭5位順序為 4.4(32.5%),5.1(19.4%),5.0 (16.2%),4.2(10%),6.0(7.5%)。
說明咩呢?就係小鴨用家,係先進嘅。
(利申:主機仲係5.0,而且仲有2.2機的相對落後份子-因為仲有0.33%用戶,仲用緊古董級的2.2,所以會繼續用來測試。)
而好快又要重寫一部份準備上N… 因為自動更新資料庫的流程中,偵測網絡轉變的部份在N將會因新轉變而失效,因此須用另外的方式進行。現有版本在Android N雖已可開啟及攔截,但估計自動下載在手機沒有網絡可用後,是可能會失效的。
是咁的,隨着小鴨DEV版有較多下載,下載小鴨的群組也較廣泛,於是便遇到之前真.小熊vs小米的類似問題,即部份機種在預設下的行為,偏離Android程序介面的協定,以致按Android標準編寫的程式,不能有效運作,同時該等手機對本身不相容於標準Android的處理方式,沒有充足地通知用戶,引致用戶認為是App本身的問題。
除了處理用戶回報的主觀感覺外,經分析Google play的數據,亦發覺到在安裝此App後再解除安裝的比率,有上升現象。當然有很多原因,可以導致解除安裝的比率上升,例如一開始便支持小鴨的用戶群組,與後來的用戶群組,組合有所改變(與Youtube不同,Google play developer console沒有人口分析),或者隻App本身相對差了,又或者好多用戶真係頂唔順隻小鴨。但由於Google Play的解除安裝統計數據,有按機種的分項統計,因以可以用來做下偽科學粗略的分析,看看機種是否有影響。
於是,在Google play下載了2016年5月的統計數據,再分項計出每一機種在5月的安裝及解除安裝數字。雖然理論上這兩組數不能直接比較,(解除安裝數字中包括5月之前安裝的用戶,而5月沒有解除安裝也可在之後解除),不過暫且當兩項因素可互相抵消,以作估計。
用了較簡單(而且LibreOffice Calc有現成function)的方式分析(利申:中學之後沒有再學統計):按上述假設,先以「5月解除安裝數字總數」除以「 5月安裝數字總數」,得出5月整體解除安裝比率為p,再將每一機種的安裝及解除安裝的情況,當作為binomial distribution,從而計一下,該機種解除安裝數字等於或高於觀察到的數字,而仍符合「解除安裝比率為p」這項null hypothesis(H0)的機會率(再利申:中學沒有學chi-squared呀ANOVA呀個的,認真看你便輸了)。換句話說,這個數字愈細,該機種解除安裝的情況,便有愈大機會,在去除隨機因素後,仍無法用各機種的平均數來解釋(或曰,否定背後binomial distribution模型的平均比率為p)。
以下為上述算法得出,從最細數字結果起各機款的排名,可大致粗略理解為,排位越高,更肯定是因為機種的影響而較多人解除安裝:
(code name是實際用以分析、較為細分的機型,同一款機如Note5可以對應多個code name):
機款 | Code name | H0機會率* |
---|---|---|
Samsung Galaxy S6 Edge+ | zenlte | 0.014% |
Samsung Galaxy S5 | klte | 0.027% |
Samsung Galaxy J5 | j5lte | 0.032% |
Samsung Galaxy Note 4 | trhplte | 0.061% |
Samsung Galaxy Mega2 | vastaltezh | 0.15% |
Samsung Galaxy A8 | a8ltechn | 0.15% |
Huawei X2 | HWGemini | 0.18% |
Xiaomi Redmi Note 3 | hennessy | 0.63% |
Xiaomi MI NOTE LTE | virgo | 1.37% |
Samsung Galaxy Note 5 | nobleltehk | 1.61% |
Xiaomi HM NOTE 1W | lcsh92_wet_jb9 | 2.10% |
Xiaomi MI 3W | cancro | 2.57% |
Xiaomi HM 2LTE-SA | HM2014817 | 3.55% |
[還有Sony Xperia M2 (D2303)解除安裝數高於安裝數,應屬此類,不過沒有數可計]
以下為相對較多人用,而排名較後的機種
機種 | Code name | H0機會率 |
---|---|---|
Samsung Galaxy Note 3 | hlte | 56% |
Samsung Galaxy Note 2 | t0lte | 76% |
LG G Pro 2 | b1w | 78% |
LG G5 | h1 | 89% |
LG G4 | p1 | 92% |
Samsung Galaxy S4 | jflte | 92% |
Samsung Galaxy S7 | herolte | 98% |
Xiaomi Redmi Note 3 | kenzo | 98% |
LG G3 | g3 | 98% |
LG V10 | pplus | 99.99% |
(另外兩大牌子較少用戶,數字沒有那麼肯定:不過HTC差不多全在50%以上,而Sony分佈較較廣但除上述Xperia M2外都是分佈在5%至100%)
注意,少人用的機種,會有較大隨機因素,因此較多人用的機種,才有較大機會到達榜首/榜尾,即較易肯定是機種的影響,而5月安裝小鴨用戶以Samsung及LG較多(可能反映本地整體情況)。
即使解除安裝比率偏離平均數,也可以有很多不同原因可解釋,未必是手機本身的機能不兼容引致,例如新出機種,或某類品牌的機種,可能吸引較多「要求較高」或「勇於嘗試」的用戶群,而這群組本身,可能較傾向嘗試不同的App的用家,因此可能提高了解除安裝比率。(反過來說,某些群組也可能較為熟悉如何正確設定不同機款,較不會遇到兼容問題而要解除安裝)。
不過即使有上述假設及須注意之處,結果似乎仍相當明顯地,顯示三叔差不多全線較新的機款,皆引致特別多人安裝小鴨後會解除安裝,比小米更嚴重,與集中在另一端,另一主流牌子LG的新機款,有明顯差別。兩者的分別,似乎是系統性的,加上三叔部份較多用戶舊機款,如Note 2及Note 3,卻不在榜首,似乎很難以上面的用戶群組因素,或其他巧合的原因,作合理解釋。
雖然單憑以上的觀察未必能就背後原因作出概括結論,但比較榜首及其他位置的主要機款,一大分別就是開首提及的,機種對背景處理與標準Android不相容問題。小米相信不用多說,而三叔則好學唔學,將北京「猎豹移动」公司的「猎豹清理大师」,即係在香港只用英文名,並大做廣告成功吸引大批用戶的馳名國際的 “Clean Master” App的「技術」,隨機附送,令背景攔截可能因被「優化」(背景處理終止)而失效。這「技術」只在三叔新機種或較舊一點的機款最近更新的ROM中附送,與上述觀察大致刎合,而最賤格的是令人頭痛的,包括(1)該「大师」程式在機內的名稱及設定功能的位置,會隨機種而異,而且同一機款同一Android版本,因應不同ROM更新版本,可能只有部份有該「優化」機能,(2)和小米一樣,該「優化」機能破壞與Android的兼容性,卻沒有予用戶警告,而受影響App亦似乎無法讀取有關設定並提示用戶,(3)明明是殺掉背景處理,卻說成是「最佳化」/「優化」該程式,一般用戶找到該設定也不容易理解。 (作為比較,Android 6 本身另一完全不相關的功能,稱作電池優化而不是優化某程式)(4)預設更可能會於沒有開App數日後才自動生效(部份可選3,5或7日),結果造成一時work一時唔work的現象,難以捕捉,更令人懷疑是App本身的問題而不是系統作怪,比小米一開始便失效還差。
再次強調,上述只是一般性推斷,當中也有幾個例外的情況:(1)Sony Xperia M2的解除安裝比率相當高,但不知何故,可能是有其他相容問題,又或者有人用此機種做某種試驗?(2)Galaxy S7及Redmi Note 3應有同樣問題,但解除安裝率較平均低,不清楚是該批用戶較熟手懂設定?還是剛安裝仍未發覺問題?待有更多數字再看看。(3)榜首的三叔機,部份用戶可能仍未收到/安裝該「優化」機能,而另一方面,不在榜首的Note 3,應陸續更新到Android 5並附送該機能。
由於我不是大機構,不能長期研究及收集各種新款手機的不同「優化」設定及方法,再在Google Play重覆做人肉剪貼機,代替廠商去警告/教育用戶,注意有關設定,(而且證明很多人沒有看我Google Play上長篇大論教人設定的說明),因此在得出上述似是而非的大堆數據加上懶係科學咁印證了自我預設的結論後,在有較好解決辦法前,只好出此下策以保障用戶體驗:暫時將主要懷疑有問題的機種,列為與小鴨不相容,以反映這事實,並將這項偉大的教育工作留給其他較多資源的App,呢的廣告費抵你賺嘅。這會令有關機種在Google Play中找不到此App下載,受影響的主要是Samsung新機種,小米(及其他內地機種),還有部份Zenfone 2(因為預設不會自啟動)。受影響用戶仍可於此網站下載APK自行安裝,相信找到此APK並懂得安裝的用戶,對正確設定不會有大問題。
為讓原有用戶可繼續用Google Play升級,有關限制會在日後新版本推出時暫時解除。此措施會按最新數字持續檢討,因為也有可能證明,解除安裝比率的差別是與其他因素有關。
注意這不是停止對有關機種支援,只是確保相關機種用戶,下載此App前先了解設定方法。
對原本懂得設定或會看Google Play說明的用戶,帶來不便之處,敬請見諒。
此外,歡迎提供在Google Play說明中沒有提及的機種/設定方法。
目前對Android 7支援主要為確保運作上的相容性,稍後會增加其他支援。而其實Android 7內部已具有攔截電話API,但只限預設電話程式使用,由於電話程式須與電話本身高度配合,一般用戶不會用第三方軟件,相信只是Google(或手機廠商)自行設立攔截電話資料庫預留的接口。
0.2.8版加入了說好的匯出自訂名單功能,方便用戶換機時將原有名單儲存,再在新機匯入。
注意:
此外0.2.8版亦更新了IDD資料。
因應有報導指,有「電話攔截」程式會上載用戶通訊錄,以建立資料庫作「反查」來電功能,特此聲明-
「小鴨幹線」程式取得的「通訊錄」權限,僅用於
再次重申,以上各項,均不涉及將通訊錄上載至任何地方作任何用途。
此外,「小鴨幹線」程式亦遵照Android 6或以上更安全的權限機制(即 runtime permissions)。在Android 6或以上裝置使用「小鴨幹線」程式時,程式只會在用戶使用上述(1)或(2)功能的時候,才彈出對話窗,向用戶要求授予通訊錄權限,而上述(3)的提示功能,則只會在之前已授權的情況下生效。按Android 6的設計,沒有用戶另行授權,即使下載「小鴨幹線」時已列明有通訊錄權限,程式亦無法存取用戶的通訊錄(換句話說,用戶須另行opt-in,「小鴨幹線」程式才可存取通訊錄)。
因此,在Android 6或以上,若用戶不使用上述通訊錄相關的攔截條件或功能,便不用向「小鴨幹線」授予通訊錄權限。而即使已授予通訊錄權限,在不再使用相關的攔截條件或功能時,亦可在系統設定中撤回通訊錄權限,而不影響其他運作。
「小鴨幹線」中使用的第三方軟件庫,全屬開源軟件,沒有廣告網絡或其他供應商的非開源軟件庫,而且除直接從Google下載的軟件庫外,大部份為作者自行編繹,因此可以相當肯定[1],沒有第三方軟件可利用「小鴨幹線」程式的權限,取得用戶私隱資料。
最後,「小鴨幹線」為香港出品,直接受香港私隱法例所管轄,(亦受不誠實使用電腦等法例規管),作者是絕不會以身試法的。
有關「小鴨幹線」其他權限的簡介,可參閱此頁最後一節的權限說明。
[1]除非出現Google供下載的軟件庫或編繹器被偷換,或作者Linux電腦被專門感染apk的惡意軟件入侵等意外。
因應近日關注,茲根據Google Play上資料,列出部份來電攔截/反查App在Android 5.0或以上安裝時要求的權限及相關資料,以供參考。
(「小鴨幹線」不具一般非廣告來電的反查功能。僅列出Google官方定義的權限,不包含非官方的自定義權限)
小鴨幹線 0.2.8 | 小熊來電 5.6.8 | Whoscall 5.7 | Truecaller 7.72 | |
---|---|---|---|---|
Android目標版本[1] | Android 7.0 | Android 4.3 | Android 6.0 | Android 7.0 |
下載程式檔(APK)大小 | 2.9MB | 16.6MB | 19.9MB | 8.7MB |
權限 | ||||
應用程式內購買 | 需要 | 需要 | 需要 | |
裝置和應用程式記錄 | ||||
擷取執行中的應用程式 | 需要 | 需要 | ||
身分識別 | ||||
找出裝置上的帳戶 | 需要 | 需要 | 需要 | |
新增或移除帳戶 | 需要 | 需要 | ||
讀取自己的聯絡資料 | 需要 | |||
通訊錄 | ||||
找出裝置上的帳戶 | 需要 | 需要 | 需要 | |
讀取您的通訊錄 | 需要 | 需要 | 需要 | 需要 |
修改您的通訊錄 | 需要 | 需要 | 需要 | 需要 |
日曆 | ||||
讀取日曆活動及機密資訊 | 需要 | |||
位置 | ||||
約略位置 (以網絡為基準) | 需要 | 需要 | ||
精確位置 (以 GPS 和網絡為基準) | 需要 | 需要 | ||
短訊 | ||||
讀取文字訊息 (SMS 或 MMS) | 需要 | 需要 | ||
接收文字訊息 (MMS) | 需要 | 需要 | 需要 | |
接收文字訊息 (SMS) | 需要 | 需要 | 需要 | |
傳送 SMS 短訊 | 需要 | 需要 | 需要 | |
編輯文字訊息 (SMS 或 MMS) | 需要 | |||
手機 | ||||
直接撥打電話號碼 | 需要 | 需要 | 需要 | 需要 |
直接撥打任何電話號碼 | 需要 | |||
讀取手機狀態和識別碼 | 需要 | 需要 | 需要 | 需要 |
寫入通話記錄 | 需要 | 需要 | 需要 | 需要 |
讀取通話記錄 | 需要 | 需要 | 需要 | 需要 |
修改手機狀態 | 需要 | 需要 | ||
重新設定撥出電話的路徑 | 需要 | 需要 | ||
新增留言 | 需要 | |||
相片/媒體/檔案 | ||||
修改或刪除您 USB 儲存空間中的內容 | 需要 | 需要 | 需要 | 需要 |
讀取 USB 儲存裝置的內容 | 需要 | 需要 | 需要 | 需要 |
儲存空間 | ||||
修改或刪除您 USB 儲存空間中的內容 | 需要 | 需要 | 需要 | 需要 |
讀取 USB 儲存裝置的內容 | 需要 | 需要 | 需要 | 需要 |
麥克風 | ||||
錄音 | 需要 | |||
Wi-Fi 連線資訊 | ||||
查看 Wi-Fi 連線 | 需要 | 需要 | 需要 | |
裝置識別碼和通話資訊 | ||||
讀取手機狀態和識別碼 | 需要 | 需要 | 需要 | 需要 |
其他 | ||||
使用任何媒體解碼器進行播放 | 需要 | |||
繫結至通知偵聽器服務 | 需要 | 需要 | ||
不顯示通知,直接下載檔案 | 需要 | |||
MMS 喚醒 | 需要 | |||
讀取留言訊息 | 需要 | |||
寫入留言訊息 | 需要 | |||
啟動時執行 | 需要 | 需要 | 需要 | 需要 |
讀取同步處理統計資料 | 需要 | |||
讀取同步處理設定 | 需要 | |||
開啟和關閉同步功能 | 需要 | |||
接收互聯網資料 | 需要 | 需要 | 需要 | |
控制震動 | 需要 | 需要 | 需要 | |
停用屏幕上鎖 | 需要 | 需要 | 需要 | 需要 |
修改系統設定 | 需要 | 需要 | 需要 | |
覆蓋其他應用程式 | 需要 | 需要 | 需要 | 需要 |
控制近距離無線通訊 | 需要 | 需要 | ||
更改音效設定 | 需要 | 需要 | 需要 | |
防止裝置進入休眠狀態 | 需要 | 需要 | 需要 | 需要 |
查看網絡連線 | 需要 | 需要 | 需要 | 需要 |
更改網絡連線 | 需要 | |||
全面網絡存取權 | 需要 | 需要 | 需要 | 需要 |
建立帳戶及設定密碼 | 需要 | 需要 | ||
安裝捷徑 | 需要 | 需要 | ||
使用裝置上的帳戶 | 需要 |
有關「小鴨幹線」權限的簡介,可參閱此頁最後一節的權限說明。其他App的權限請參考相關App的條款及說明。
此版本針對近年每日打出數以百萬高頻來電推銷,每天更換電話,長期在HKJunkcall榜首的撥電話手法,將疑似登記並用以每天打出過大量電話的區段,提供予用戶選擇攔截。
注意:
此版本亦更新了IDD資料,修正了一些較少出現的問題(如不能回撥來電),稍為改良界面,及更新了資料庫的程式庫,(小鴨亦會順便提提大家就政府的推銷電話諮詢交意見!)
最近有多宗用戶回報,指小鴨在華為Mate 10 /Pro上,不時會停止運作,即使做足保護App免被終止的設定(如在電量關閉自動管理及設定權限),以至在多工畫面鎖App,以及開啓App內顯示服務通知(即表示程式屬前景服務,非必要不應殺掉),仍未能阻止華為自訂的系統在一段時間或鎖機後,停止小鴨的正常運作。
作者並無華為手機驗證,但根據回報所描述,再查閱網上討論(包括背景App,或運作相近的Widget及即時通知),似乎相當多華為Mate 10 /Pro 用戶(以至升級到EMUI
8的其他華為手機用戶)遇到相似問題,即這類App正常運作一段時間後會停止運作,更改省電設定很多時並沒有解決問題,更混亂的是,省電設定的效用似乎因用戶及App而異,如部份用戶發覺,某些App在開啟電量自動管理後反而更能持續運作。
EMUI凍結背景App的機制(註1),顯然不是原生Android本身的設計,應與Android 8加強背景運作控制無關(況且Android 8的新限制只適用於target Android 8或以上的App而小鴨目前仍不是)。雖然華為在EMUI
8之前亦有採用類似機制,但或許由於在EMUI 8上更「進取」,引致背景運作受嚴重影響,即使是華為Mate的舊用戶,在Mate 10也未能成功設定防止背景App被凍結。
有討論指,這可能是因為華為Mate 10採用所謂AI省電,透過學習用戶習慣自行決定可停止/凍結什麼App。用戶若較常開啟某App便會減少該App被停止的問題。但這樣的所謂AI學習,似乎是建基於完全錯誤的假設,就是用戶不開啟、沒有interaction的App,在背景運作便是浪費電量,而疑似AI省電看來能凌駕用戶的省電及鎖定設定,這若不是bug,便是假設了AI比程式開發者及用戶更清楚運作要求。
而諷刺地,若上述理解為真,用戶要用攔截電話軟件,或須將省電設為自動後,不時開啟攔截程式做些動作,以「訓練」AI不要停止其背景運作,才可較可靠地長時間運作。而且即使成功,若日後疏於「訓練」,亦可能故態復萌。這種耗電耗時費心但仍沒有保證的做法,恰恰將省電及攔截軟件兩者的好處完全廢掉。
另一種做法,是root機後再用方法停止華為的休眠機制(註1文章有介紹mate 9做法),不過,除了root機的風險,由於觸及隨時會改變的底層細節,變磚風險自負。
所以,如果購入AI能凌駕用戶設定,停止App運作的手機,便要有幫襯電訊商攔截服務,才能有效攔截推銷來電的覺悟。
(20/1/2018)現已將Mate 10及Mate 10 Pro在Google Play上列為不兼容,以免用戶誤會可正常運作。若要測試可直接下載APK。
註1:
在XDA早幾天一篇貼文,研究了Mate 9 停止App運作的底層機制,發覺華為在Android本身的記憶及進程管理之外,直接使用了Linux的休眠機制,去凍結App的進程,(在Mate 9上透過華為「Phone Manager」進行),與Android原生的機制不同,App在Mate 9被凍結後,不會停止再重啟,而是待收到內部訊息時解凍。有人隨後發現Mate 10也有類似休眠機制。該文指,此機制無法透過華為設定關掉。作者隨後指,或可用如AutoMagic的App,每十秒喚醒程式一次以防止被休眠。(如不介意核電變倒水電⋯⋯)雖然此機制下,「解凍」時App不用重新初始化,但或會導致已過時的事件一次過觸發,引起其他問題(如攔截App彈出過時的來電提示,紀錄錯誤時間等)。
據XDA近日一篇文章,Xposed作者rovo89發現,Google在Android源碼(AOSP)中,剛加入了新的機制,目的很可能是禁止一般App在下一版Android中,使用在AOSP源碼中標注為隱藏(@hide
)的應用程式介面(API)。
XDA文章 : https://www.xda-developers.com/google-undocumented-hidden-apis-android-p/
如該文所述,由於部份Android的功能,由於沒有正式的API,一般App目前只能透過用特別方式(如Java reflection)呼叫隱藏API才能使用。因此在Android P及以後,除非Android另行提供正式的公開介面,否則Apps或將不可再使用這些受影響的功能。
不幸的是,電話攔截的其中一項核心功能 ╴電話掛線,目前只能透過隱藏API使用[1]。
雖然Android N起,提供了正式的攔截API,包括 BlockedNumberContract
,供App加入攔截名單,由系統攔截 ╴好處是,由於名單是系統功能的一部份,App不用於背景運作,沒有殺App問題;但是,該名單只限由用戶設為預設的電話撥號/短訊程式,或有電訊商權限的程式(配合SIM Card)存取。另外,預設電話撥號程式亦可實作 CallScreeningService
的API,指示系統如何處理電話。
因此,Android P及以後,目前的攔截軟件若不轉型,便可能會失去攔截功能,只能將電話轉為靜音或彈出提示(如無加入其他進一步限制的話)。
一般攔截App沒有電訊商權限,要使用正式API的掛線功能,攔截App便要加入撥號或短訊功能,並由用戶選擇成為預設電話撥號/短訊程式[2]。
但一般用戶,絕少會更改跟機的預設撥號程式,因為首先多了設定要做,亦會出現兼容問題,而即使兼容,亦會失去很多配合機款或較先進的功能。而第三方軟件UI介面亦可能與系統格格不入。此外,撥號及短訊軟件亦需要更進一步的權限,引起憂慮(雖然目前攔截軟件已須大量權限)。
當然,若Android另行為攔截軟件提供電話掛線的公開介面,便沒有以上問題。
但觀乎在Android O起,Google加入接聽電話的正式API及相關權限,但並無加入相關的掛線的正式API,而Android P發展中的源碼,只見有意加強系統本身的攔截機制,(如加入攔截不在通訊錄電話的機制),卻沒有開放掛線API的跡象。似乎Google有意將目前攔截App的功能,納入系統機制中,但機制主要是為電話廠商和電訊商提供攔截服務而設。
這合乎Google一直收緊對第三方App背景運作及權限的趨勢,尤其是不時傳出某些來電反查軟件,一直有上傳用戶通訊錄的私隱問題,Google逐步收緊此類軟件的空間也不為奇。
反觀iOS,在版本iOS 10以後,已開放API給一般App攔截電話(以預先設定名單方式),不用改變dialer(因為iOS不會容許第三方dialer)。以往iOS用戶羨慕Android可簡單攔截電話,iOS則要用迂迴方式並只能彈出提示,或光顧電訊公司的服務,風水輪流轉,日後情況可能要反轉。
[1] App目前要透過Reflection,呼叫
TelephonyManager
中的getITelephony
,以取得ITelephony
內部電話服務的實作,再藉此呼叫掛線功能。Stackoverflow上有關該隱藏API的相關細節 :
https://stackoverflow.com/questions/1083527/how-to-block-calls-in-android
https://stackoverflow.com/questions/20965702/end-incoming-call-programmatically
[2] 如用戶能接受使用攔截軟件作為短訊軟件,即可使用Android N加入的
BlockedNumberContract
機制,好處是短訊軟件可能較撥號程式易取得兼容,但由於BlockedNumberContract
機制是以預先設定黑名單的方式運作,不能藉規則(如某字頭)進行,現行功能會打折扣(如不能攔截「+」開頭的電話)。而使用
CallScreeningService
機制則較靈活,可按實際號碼判斷是否攔截,但只能由透過成為預設撥號程式進行。