最近、iosの3GやLTEのネットワーク周りはどのように制御されていて、実際高速化やバッテリーの最適化をアプリごとでできないか、調査してみようと思ったので、ちょっと前知識と調査に必要そうなものをまとめてみた。
3G通信の通信制御方式には複数ある
Fast Dormancy と Network Controlled Fast Dormancy
それぞれ、
Fast Dormancy: cell_dch, cell_fach, Idle
Network Controlled Fast Dormancy: cell_dch, cell_fach, cell_pch, Idle
の状態がある。簡単に言うと、
cell_dch: 上りも下りも高速通信状態
cell_fach: cell_dchよりも遅く、上りはランダム通信。下りは常時通信。
cell_pch: ネットワークの接続を維持していて、上りは通信していなく、下りのみ一定間隔で基地局から信号を受信する状態。
idle: アイドル状態。
Network Controlled Fast Dormancyはcell_pchという中間領域を作ることで、ネットワーク側とのシグナルの量を削減している。
idleからcell_dchへの遷移へ必要なシグナルが30シグナルに対して、cell_pchからcell_dchへの遷移へ必要なシグナルが12シグナルになる。
cell_dchからcell_pchへの遷移はネットワーク側で制御されているため、端末側ではidleからcell_dch、cell_pchからcell_dch、cell_fachからcell_dchへの遷移を最適化するか、あとはcell_fachを極力以降させずに通信時cell_dch状態を保ち続けるように最適化することを考えていくのが良さそうだ。
また例え、Network Controlled Fast Dormancyを実装したOSであっても、ネットワーク側がそれに対応していないと結局Fast Dormancyとして扱われるんじゃないかと思うので、日本だけじゃなくて海外のネットワークを考慮するためには、
この2つの通信制御方式の壁をちゃんと認識していた方が、ネットワークのローカライズとかにも便利なのかも。
LTE通信の通信制御方式と3G通信との違い
※ これは別途記述する。
iosで通信系を調査するための準備
Reachability
appleが昔からsample codeとして提供しているReachabilityだが、このPrintReachabilityFlagsメソッドで表示しているflag statusが利用できそう。
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
//#if kShouldPrintReachabilityFlags
NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
comment
);
//#endif
}
例えば、iosエミュレータなら
2015-08-19 21:35:17.550 NetworkCheck2[4634:4375998] Reachability Flag Status: -- t------ currentFlag
2015-08-19 21:35:18.553 NetworkCheck2[4634:4375998] Reachability Flag Status: -- tcC-D-- currentFlag
で通信状態が変化する。
CoreTelephony.framework
シグナル情報の取得
ios7から新たに利用できるようになったframeworkである。
このフレームワークを利用することによって、制御シグナルを確認することができるようだ。
int CTGetSignalStrength();
@implementation NetworkObserver
- (void)monitoringSignalStrength {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
while (true) {
printf("signal strength: %d\n", CTGetSignalStrength());
sleep(1);
}
});
}
例えば、cell_pchからcell_dchへのシグナル数は12とわかっているから、そこから状態の逆算ができるかもしれない。
ネットワークの変更観測とネットワークの種類
ネットワーク自体の変更が観測できるようにobserverを仕込む。
typedef enum : NSInteger{
NONotReachable,
NONetworkStatusWifi,
NCNetworkStatus2G,
NONetworkStatus3G,
NONetworkStatusLTE
}NONetworkStatus;
@property (weak) id myObserver;
---------
@implementation NetworkObserver
- (void)addObserverForNetworkChange{
CTTelephonyNetworkInfo *telephonyInfo = [CTTelephonyNetworkInfo new];
NSLog(@"Current Radio Access Technology: %@", telephonyInfo.currentRadioAccessTechnology);
self.myObserver = [NSNotificationCenter.defaultCenter addObserverForName:CTRadioAccessTechnologyDidChangeNotification
object:telephonyInfo
queue:nil
usingBlock:^(NSNotification *note){
CTTelephonyNetworkInfo currentTelephonyInfo = (CTTelephonyNetworkInfo *)note;
NSLog(@"New Radio Access Technology: %@ \n Network Kind: %d", telephonyInfo.currentRadioAccessTechnology, [self currentNetwork:currentTelephonyInfo ]);
}];
}
- (void)removeObserverWithTelephonyNetworkInfo{
[[NSNotificationCenter defaultCenter] removeObserver:self.myObserver];
}
- (NCNetworkStatus)currentNetwork:(CTTelephonyNetworkInfo*)networkInfo{
Reachability *reach = [Reachability new];
if (reach.currentReachabilityStatus == NotReachable) {
NSLog(@"No network access");
return NONotReachable;
}else if (reach.currentReachabilityStatus == ReachableViaWiFi) {
NSLog(@"Wifi Connection");
return NONetworkStatusWifi;
}
if ([networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]
) {
//NSLog(@"2G");
return NCNetworkStatus2G;
}else if ([networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA] ||
[networkInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]
) {
//NSLog(@"3G");
return NONetworkStatus3G;
}
//NSLog(@"LTE");
return NONetworkStatusLTE;
}
ちょっと雑だけど、こんな感じかな。
だいたい準備はできたので、次回以降これらを利用してネットワークを制御状態を確認していきたいと思う。