PC自身を認証器に使うというニーズ

とあるところでMFA(Multi-Factor Authentication)への対応方法の説明で、

ワンタイムパスワード方式で使うアプリとしてWinAuthが例示されていた。

Google Authenticatorを差し置いて筆頭で書かれているのだが、

聞いたことがないので調べてみた。


調べたらすぐにわかったのだが、Windowsで動く認証アプリだった。

機能的にはGoogle Authenticatorとほぼ同じ。

それと同じことがWindows上でできるだけのことである。

WindowsでTOTPを表示させるという発想がなかったのだが、

そういうアプリがあって、そういうニーズがあるということらしい。


どうも説明を読むと、クラウドアプリケーションを使うPCでWinAuthを導入し、

WinAuthでTOTPをコピーして、クラウドアプリにペーストして使うと。

そういう使い方を想定しているようである。

このため2要素認証の1つがPCの中に搭載されてしまうのがセキュリティ強度として弱いかもしれないみたいな指摘は書かれていた。


ただ、クラウドアプリへのログイン認証の強固化にはけっこう効くかもしれない。

MFAを使わなければ、ID・パスワードが揃えばどこのPCからでもログインできる。

ワンタイムパスワード方式にすると、ワンタイムパスワードの生成器も必要となる。

その生成器がスマートフォンなのか、クライアントPCなのかはわからないが、

これらの実体をハードウェアを持っていない人が不正にログインすることは困難になる。


一方でPC自体を認証器にするのにワンタイムパスワードを使うのも違和感はある。

例えばTLSクライアント証明書とか。(cf. クライアント証明書で通す)

ただ、こういう仕組みは想定していないようである。

FIDOセキュリティキーを使う方法だと実質的にそんな感じになるのかも。

セキュリティキーはUSBやNFCで必要時に接続して使うことが想定されているが、

ところによってはクライアントPCに固定する形で使っているかも知れない。

こうするとクライアントPCからのログインのみ通すというのに実態として近くなる。


というわけでPCを認証器に使うというのも意味はあるが、

それならそれでもっといい方法があるんじゃない? とは思った。

ただ、他の方法との互換性を考えればこれが使いやすいというのも理解できる面はある。


まぁデスクトップPCだとデバイス自体の盗難対策はやりやすい面もある。

鍵で固定するとかそういう対策が効果的なので。

その点では認証器としてデスクトップPCを使うことは必ずしも悪くはない。

ただ、他のPCからログインする場合など、認証器を持ち運べないことの不便さもあるかもしれない。

スマートフォンを認証器に使うなら、そのスマートフォンの管理体制の問題もある。

そこら辺を考えてどれがよりよい方法かは考えるべきなのだろう。


少なくともWinAuthはスタンドアロンでワンタイムパスワードを管理できるという点では効果的である。

HMAC-based TOTPはソフトウェア的に容易に計算できるので、

ワンタイムパスワードのマネージメントをクラウド上で行う仕組みもある。

Authyとか1passwordがそのような仕組みを使っているとか。

しかし、この場合はワンタイムパスワードを管理するサービスの管理が問題になる。

ここが他の人に盗まれてしまっては結局意味がないというわけである。

スタンドアロンならその端末が盗まれなければとりあえずよいと言える。

その点ではWinAuthを使えば、これで妥当だという説明はしやすいと思った。

ARMのゴテゴテした命令

ARM Cortex-Rを触っている話を書いているが、

アセンブラを触っているとサンプルコードにこんな命令が。

ldrhne r0, [lr, #-2]

ldrhneって一体どんな命令だと調べてもすぐには出てこない。

実はこれldr命令に2つの装飾が付いているのだ。


ARMの命令は基本的な命令にいろいろな付加機能を付けることができる。

1つが条件付き命令である。

プログラムでは演算結果に応じて処理を分岐することはよくある。

前の演算結果でZフラグが0(演算結果が0以外、引き算して0以外は不一致を表す)でLABEL1に分岐するのは、こう書く。

bne LABEL1

実はB命令をNE(Z=0)という条件で装飾したものという位置づけである。

なので、他の命令も多くはこういう装飾ができてしまう。

movne r0, #10

MOV命令をNEで装飾し、Z=0のときにr0に10を格納するという意味になる。

1命令やるかやらないか程度ならジャンプしなくてよいと。


各種演算命令では結果に応じてフラグを変更して分岐などに使うことができるが、

そのようなフラグを変えたくないというニーズもありうる。

各種の演算命令にSを付けるとフラグに反映するというルールがある。

subs r0,r0,r1
sub r2,r2,r3

こうやって並んでいるとr0-r1の計算結果に応じたフラグが残ると。

さらに各種の命令にはビットシフトを装飾できる。

orr r0,r0,r1,lsl #3

これで r0=r0|(r1<<8)というような操作になる。

なので単なるビットシフト命令はmovのエイリアスという扱いになるそうで、

lsl r0, r0, #3
mov r0, r0, lsl #3

上の書き方をしても下の書き方に相当する命令が生成されると。


メモリ上のデータをレジスタに格納するLDR命令にはビット幅のバリエーションがある。

ldrhだとハーフワード(16bit幅)、ldrbだとバイト幅と。

さらに符号拡張との組み合わせもあって、ldrshだと符号付きハーフワードと。

あと、参照先のアドレスへの加算も1命令で書けてしまう。

ldr r0,[r2, +#2]
ldr r0,[r2, r3, lsl #2]

なんて書き方をすると r0=*(r2+2) とか r0=(r2+r3<<2) のような意味になる。

レジスタの値をビットシフトして加算するというのは配列の参照で出番が多い。


で、冒頭に書いたのは ldr + h + ne と分解して読むことが出来て

メモリ上のlr+2のアドレスにある値をハーフワードで読んでr0に格納する、

という動作をフラグがZ=0の場合のみ実行するということを表している。

ゴテゴテした命令なので単純に調べてもひっかからないが、

分解すると実はそういう意味があると。


この命令、調べてみるとSVCハンドラのサンプルコードがひっかかる。

msr r0,spsr
tst r0,#0x20
ldrhne r0,[lr,#-2]
bicne r0,r0,#0xFF00
ldreq r0,[lr,#-4]
biceq r0,r0,#0xFF000000

実はSVC割り込みでSVC番号を確認するには、命令を確認しないといけない。

しかも厄介なことにCortex-M以外ではSVC命令が2種類考えられる。

1つは32bit固定のARM形式の命令、もう1つは可変長のThumb形式の命令。

SVC命令はThumb形式ならば16bitで表される。

そこで、SVC割り込み前のフラグ(SPSR)を見て、Tビットを判定する。

TビットはSVC割り込み前にThumb形式の命令を実行していた否かを表す。

lrレジスタには割り込みからの復帰先のアドレスが入っているので、

lrより1つ前の命令はSPSR.T=1の場合は-2、SPSR.T=0の場合は4引けばよい。

SPSR.Tの判定結果に応じてSVC命令部分をレジスタにロードする方法を分けていると。

それでARM命令だと下位24bit、Thumb形式だと下位8bitがSVC番号になっているので、

これを抽出するのにbic命令を使っているが、これも条件に応じて分けている。

bic命令は指定されたビットをクリアするという意味である。


Thumb形式で書かれたプログラムへジャンプするときは、

アドレスを奇数アドレスにすることで識別するという考えがある。

Cortex-MではThumb形式だけをサポートするから、プログラムは奇数アドレスでの表記ばかりになる。

こういう命令セットの使い分けも面倒な話である。

ちょっとこれでひっかかったところがあった。


というわけでARMはいろいろゴテゴテしているという話だった。

こんなの手で書こうって言っても無理があるので、

普通はコンパイラに任せればよいのだが、どうしてもアセンブラで書かないといけないところもある。

こんな条件付き命令とかガリガリ使うアセンブラを読み書きするのは初めてで、

なんだこれ? となるのも仕方ない話である。

割り込まれたらSVCモードに戻る

先日、ARM Cortex-Rシリーズの話を書いた。

Cortex-Rシリーズはめんどくさい

チームメンバーと役割分担しながら作業を進めている。

主に割り込みハンドラの部分をCortex-Aのコードを参考に書いていたのだが、

チップの仕様差を吸収するのがけっこう大変なのでは?

と思ったが、いろいろ掘り下げていくと、結局は当初のCortex-Aのコードと同じようになってしまうという。


サンプルコードを限りなく流用したわけだが、気になることがあった。

以前、紹介したがCortex-A, Cortex-Rにはこんな仕組みがある。

Cortex-RではUSR, FIQ, IRQ, SVC, ABT, SYS, UNDの7つのモードがある。

リセットとSVC割り込みがあるとSVCモードに、FIQ割り込みがあるとFIQモード、IRQ割り込みがあるとIRQモードに、未定義命令例外でUNDモード、アボート例外でABTモードに入る。

これらの5つのモードにはr13,r14,spsrレジスタが独立に存在する。(略)

割り込みが入るとレジスタバンクを切り替えて、割り込み前のプログラムカウンタをr14、プロセッサ状態を表すcpsrをspsrに格納する。

このようにレジスタバンクの切替とレジスタ間の転送で退避処理をすると。

この仕組みを効果的に使うためには、割り込み前のモードが重要である。


で、このプログラムは基本的にSVCモードで動くらしい。

ちなみにリセットハンドラに入る時にもSVCモードだそう。

で、IRQ割り込みが発生すると、次のような退避処理を行う。

  1. spsr_irq, r14_irqに退避されている割り込み前のcpsr, pc をSVCのスタックに退避 (SRS命令)
  2. SVCモードに切り替える (CPS命令)
  3. r0~r3, r12, r13_svcを(SVCの)スタックに格納する (STM命令)

サンプルコードを解読していて、SRS命令には驚いた覚えがある。

なんとIRQモードでSVCのスタックポインタが操作出来てしまうという。

これに相当する処理を他の方法で書くと相当めんどくさいはず。

で、ここでSVCモードに切り替えたことで、割り込みマスクを解除してIRQ割り込みが再度発生しても同様に処理できる。


これはこれでよかったのだが、SVCハンドラを見て、あれ? と思った。

  1. spsr_svc, r14_svcに退避されている割り込み前のcpsr, pc をSVCのスタックに退避
  2. r0~r3, r12を(SVCの)スタックに格納する
  3. r14_svcの代わりにダミーデータをスタックに格納する

SVCモードにいる状態で、SVC割り込みが入ると、それ以前の spsr_svc, r14_svc が上書きされてしまう。

spsr_svcは割り込み時の退避にしか使わないからよいとして、

r14_svcは普通にプログラムでも関数の戻り先などに使うレジスタなのだが、

SVC割り込みで消えてしまうので、スタックにダミーデータを格納する謎の作業をしていた。


そんなことして大丈夫なの?

気になってSVC割り込みを発生させる部分を確認したらこう書いてあった。

__asm__(“svc %0″::”i”(svc_no):”lr”);

そもそもSVCは supervisor call の略でソフトウェア割り込みの一種である。

通常はOSの機能を呼び出すために使われるものらしい。

ARMではSVC命令(昔はSWI命令と呼んでいたそう)で割り込みを発生できるが、

この書き方でlr(r14レジスタの別名)が破壊されるとコンパイラに伝わるので、

必要ならばr14レジスタは呼出側で退避してくれるようだ。

SVCは発生する場所が決まっているので、こういう対応ができるらしい。


ただ、そもそもなんでSVCモードでプログラムを動かしてるんだ?

USR, FIQ, IRQ, SVC, ABT, SYS, UNDの7つのモードがあり、

USRモードは非特権、他は特権モード。SYSとUSRは同じレジスタバンクを使う。

FIQ, IRQ, SVC, ABT, UNDの5モードはいずれも独立したレジスタバンクを持ち、割り込みで遷移する。

という事情を考えたときに、どの割り込みも入る可能性があるときは、

USRモードまたはSYSモードでプログラムを動かすのが正しいのでは?

USRまたはSYSモードのレジスタはどの割り込みが入っても無事だし。


そもそも、このプログラムは簡略化のために全て特権モードで動かす方式をとっている。

特権モードとユーザーモードを使い分けることでメモリのアクセス制限などできるが、

その必要が無い簡単なシステムを想定して省略してしまっていると。

そのこと自体は問題ないのだが、それならばSYSモードを使えばよいはず。

でも、なぜかSVCモードを使っているらしい。


他でもこういう実装例が出てくるから、わりと一般的なのかも。

SVC割り込みを発生させる側でr14を退避させれば問題ないのは確かで、

実用上の問題はないのでこのまま使おうと思うのだが、

なんでSYSモードを使わないのかというのは謎である。


何でもかんでも特権モードで動かすってどうなのよ?

という考えも最初はあったけど、今回の用途はそこを考えても仕方なくて、

全て特権モードで簡略化すること自体はそこまで珍しくないようである。

確かにCortex-Mシリーズを使ってたときもそんなこと考えたことなかったしなぁ。

実はCortex-Mでも特権・非特権という概念は存在するようで、

MPU(Memory Protection Unit)が搭載されていればアクセス制限ができるという。

実はこの部分はCortex-Rと同じような仕様だったんですね。

(Cortex-RではMPUはキャッシュアクセスのコントロールの役目もある)

簡略化した結果こうなっていると忘れなければ問題なさそうだ。

Cortex-Rシリーズはめんどくさい

最近、今までとは少し違う仕事に入っている。

その中でARMのCortex-Rシリーズのマイコンを使うことになった。

Cortex-Mシリーズはこれまでも使ってきたのだが、これとは異なる点が多い。

使う上で一番違うと思ったのが割り込み関係である。

僕が今まで触ってきたマイコンと比べるとだいぶ面倒である。


ARMというマイコンアーキテクチャが知名度を上げたのが、ゲームボーイアドバンスで採用されたことだと言われている。

この当時使われていたのがARM7TDMIというコアだったらしい。

これがARM9E(ニンテンドーDSで採用)、ARM11(初代iPhoneで採用)と発展したが、

その次はARM12とならずのCortex-A, Cortex-R, Cortex-Mの3シリーズ展開になった。

この3シリーズ展開となったことがARMの活躍の場を広めたという。


3シリーズ展開になる前のARMは携帯電話のような用途がほとんどだった。

Cortex-Aシリーズの「A」はApplicationを表す。

従来からの携帯電話などの用途を継承し、リッチなOSも動くチップである。

WindowsがARM対応したとか、AppleがMacにARMベースのAppleシリコンを搭載したというので話題になっていたが。

Cortex-Mシリーズの「M」はMicrocontrollerを表す。

ワンチップマイコンを想定したもので、かなりコンパクトに作れるという。

ARMとしてはかなり異端な構成で、命令セットは従来のARM命令ではなくThumb2命令という可変長のものだけ対応している。

安価で使いやすいということで、Cortex-Mシリーズは多種多様な製品に組み込まれている。


そして、Cortex-Rシリーズ、「R」はReal-timeを表すがイマイチ知名度が低い。

ARMの組み込み向けで普及するCortex-Mと苦戦するCortex-R (ASCII.jp)

古い記事なんですけどね。

Cortex-RシリーズはCortex-Aシリーズと似ている点が多いのだが、

リアルタイム性の高い用途で使うためにメモリ周りの構成が異なる。

Cortex-AではMMU(Memory Management Unit)を搭載している。

仮想アドレスを物理アドレスに変換する機能を持っており、高級なOSを使うなら必須だが、

複雑な仕組みであるために処理時間の大きな変動を招きかねないと。

なのでこの部分はよりシンプルな仕組みにしている。

さらにTCM(密結合メモリ)というキャッシュと同じ速度でアクセスできるメモリがあり、

容量は限られるが、これを効果的に使うことで高速かつ一定時間で処理が実行できる。

このようにしてリアルタイム性の要求される処理に対応しようとした。


しかしCortex-Rシリーズはあまり流行らなかった。

Cortex-Mシリーズはキャッシュメモリを持たないコンパクトな構成だが、

これで十分な性能が得られるならば、リアルタイム性という点では申し分ない。

で、これで足りるケースが当初ARM社が目論んでいた以上に多かったと。

浮動小数点ユニットを搭載できるCortex-M4が登場してからはなおさら。

ARMとしては特異な構成だが、これが使いやすいんですよね。

当初はキャッシュメモリを搭載しないのが特色だったCortex-Mシリーズだが、

キャッシュを搭載できてより高性能化したCortex-M7なんてものも登場。

Cortex-Rシリーズでやりたかったことがだいたい入っちゃったのではと。


冒頭に書いたようにこのプロジェクトではCortex-R5Fを使うのは決まっている。

(Cortex-R5Fは浮動小数点演算に対応したCortex-R5のこと)

ただ、チームリーダーと話していたけど、実はCortex-M4あたりで対応できる処理なのではと。

確かにそんな気はするのだが、どうしてもCortex-R5Fになる理由がある。

それは様々な都合により、利用できるチップが限られることである。

検討の結果、使うことになりそうなチップにはCortex-A53とCortex-R5Fが複数個搭載されている。

このためCortex-R5Fを処理に使い、Cortex-A53は使わないという構成になると言っている。

正直無駄が多い構成だと思うのだが、現実に買えるチップがこれだから仕方ない。

うちとは逆にCortex-A53だけを使い、Cortex-R5Fは使わない構成も多いだろう。


思うところはあるが、Cortex-R5を使うと言うこと自体はそこまで変な話でもない。

ただ、割り込み処理が今まで触ってきたマイコンに比べると面倒である。

実はこの方式はARM11以前のARMで伝統的に使われていた方式らしい。

Cortex-Aも同じなのだが、Cortex-Mシリーズでは大きく2点異なる。

1つはNVIC(Nested Vectored. Interrupt Controller)の採用。

ベクタテーブルで割り込み要因ごとにジャンプするアドレスを指定できる。

もう1つがレジスタのスタックへの待避をハードウェア的に実行すること。

マイコンに割り込みが入ったら、割り込み処理が終わったら元の処理に戻れるように必要なレジスタを退避させる必要がある。

Cortex-Mシリーズでは割り込みが入れば必要なレジスタをスタックに自動的に格納する。

これにより割り込みハンドラではレジスタ退避のことを考えずに済む。


Cortex-Rシリーズではベクタテーブルには7種類しか格納できない。

リセットハンドラ、SVC, IRQ, FIQの3種類の割り込みと、未定義処理例外、プリフェッチアボート、データアボートの3種類の例外処理にそれぞれ1つ。

FIQは高速割り込み処理で、一般的な割り込みはIRQを使うとのこと。

SVC, IRQ, FIQに複数の要因がある場合は、割り込みハンドラで識別する必要がある。

Cortex-MのNVICはIRQ要因を識別して自動的に振り分けるが、他のマイコンでは一般的な構成である。

今まで触ってきたマイコンはどれもこの仕組みだったのでCortex-Rで戸惑ったと。


レジスタの待避も異なる。Cortex-RではUSR, FIQ, IRQ, SVC, ABT, SYS, UNDの7つのモードがある。

リセットとSVC割り込みがあるとSVCモードに、FIQ割り込みがあるとFIQモード、IRQ割り込みがあるとIRQモードに、未定義命令例外でUNDモード、アボート例外でABTモードに入る。

これらの5つのモードにはr13,r14,spsrレジスタが独立に存在する。

(r13は別名sp、スタックポインタとして使い、r14は別名lr、関数の復帰先を格納するリンクレジスタとして使う)

FIQモードではr8~r12の汎用レジスタ5つも独立に存在する。

割り込みが入るとレジスタバンクを切り替えて、割り込み前のプログラムカウンタをr14、プロセッサ状態を表すcpsrをspsrに格納する。

このようにレジスタバンクの切替とレジスタ間の転送で退避処理をすると。


ただ、これはこれでイマイチな仕組みである。

結局スタックへの格納処理は割り込みハンドラでやらないといけないから。

しかもこういう処理はアセンブラで書くしかないわけである。

r0~r3, r12をスタックに格納するのがお決まりだと。

(ARMではr4~r11の汎用レジスタは関数で使う時に退避させるのがお約束)

r14とspsrは多重割り込みを考える場合に退避が必要になる。

レジスタバンクの切替、レジスタ転送で退避できるのは1モード1回まで。

IRQ割り込み処理中にIRQ割り込みがあるなら、結局スタックに格納しないといけないと。

割り込み要因の識別もそうだけど、Cortex-Mではこれに相当する作業を自動的にやってくれるのにねって。


FIQ割り込みはうまくつかえば高速処理に適するのかもしれない。

FIQ割り込みの発生要因を1種類に限定しておけば識別処理はいらないし、

FIQモードで独立して持っているr8~r12レジスタは退避せず使えるわけだし。

ただ、r8~r12が退避不要という特徴を生かそうとすると、アセンブラで書かないと難しそう。

使い道が限られるので実際のところはあまり使われていないらしい。

識別不要にするというだけならばIRQ同様の使い方でもいいかもしれないけど。


なんてわけでとにかくCortex-Mより手間がかかって仕方ない。

ただ、この記事をゲームボーイアドバンスから話を始めた理由でもあるけど、こっちの方がARMの基本なんですよね。

Cortex-Mシリーズ以外ではこの考え方は共通している。

Cortex-R5に限ると実装例などの情報も少ないのだが、Cortex-Aシリーズの情報はけっこうある。

割り込み要因の識別方式など、チップにより異なる要素もあるので、

単純に同じコードでは済まないのが面倒ではあるのだけど。

Cortex-Mシリーズの情報はもっとあるのだが、これはまるで参考にならない。


Cortex-Rシリーズの特色としてMMUを搭載していないことと書いたが、

実はCortex-R82ではMMUを搭載して使うこともできるようになったという。

Arm、プロセッサ内でOSを動作可能にした「Cortex-R82」 (PC Watch)

MMUはリアルタイム処理に使わないとしてCortex-Rには搭載しなかったが、

Linuxのような高級なOSはMMUがないと動かない。

今回採用するかなと言っているチップはCortex-A53とCortex-R5Fを搭載しているが、

こういう構成にしているのはCortex-R5FではLinuxが動かないからかもしれない。

Cortex-R82ではMMUを搭載してコアごとに有効/無効を選べる。

一部のコアではMMUを使わずリアルタイム処理、一部のコアではMMUを使ってLinuxを動かす、なんてことができますよと言っている。

なるほどと思う部分もあるけど、それって流行るのかね?

goto文のあくどい使い方

最近、仕事でとあるプログラムのソースコードを読んでいたのだが、

どうにもおかしい気がしたので詳しく解析していたら、なんとgoto文が使われていた。

それもなかなかあくどい使い方である。


goto文については多重ループを抜けるために限定的に使うような話も聞く。

for(i=0;i<loop;i++){
   for(j=0;j<loop;j++){
     if(condition){
       goto LOOP_END;
}
   } } LOOP_END:

ループを途中で抜ける場合、break文で抜けられるが、

ループを2つ抜けることを単純に書けないのでgotoを使うことがあると。

ただ、僕自身はこんな書き方したことはないし、今までの仕事でも見ることはなかったが。


まずあったタイプは終了処理へジャンプさせるもの。

while(1){
if(flag1){
   goto CMD_END:
}
if(flag2){
    goto CMD_END; } switch(mode){
   case MODE1:
break;
case MODE2;
break; } CMD_END:
close1();
}

こういう書き方は比較的ある方かもしれないが。

末尾にある終了処理にいろんなところから飛んで行くと。

実際のところ、関数途中でreturn文が入る書き方もこの手のgotoの使い方に類似する面がある。

ただ、whileループの末尾に飛ばすというのが結構あくどい気がする。


次にswitch文の中で使われたgoto文。

switch(mode){
   case MODE1:
     exec1();
     goto MODE1to3;
   case MODE2:
     exec2();
     goto MODE1to3;
   case MODE3:
     exec3(); MODE1to3:
     exec4();
     break;
case MODE4:
break; }

mode=MODE1,MODE2,MODE3で共通的な処理があるからと、goto文を使って書いていると。

switch文自体がクセの強い構文だと思うんだけど……

caseごとにbreak;で終わるのが基本ではあるけど、複数ラベル束ねる場合は、

switch(mode){
   case MODE1:
   case MODE1:
   case MODE1:
     exec4();
     break; }

のような書き方をすることが一般的に認められている。

ただ、この自由度の高さを逆手に取ってか、変な書き方をする人がいると。

気持ちはわかるけど、そんな変則的な書き方をするのはいかんだろうと。


後ろに飛ぶのではなく前に飛ぶパターンもあった。

POWERON:
   exec1();
   if(status==POWERON){
     goto POWERON;
   }
   exec2();
   if(status==POWERON){
     goto POWERON;
   }
   while(1){
     exec3();
     if(status==POWERON){
       goto POWERON;
     }
   }

フラグを検出したら初期化処理に戻るって感じの話。

関数の外でなんか処理する方法を考えるべきだと思うのだが……


そして問題はこの関数というのが1000行を超えるような巨大なものであること。

というわけで解析ツールでフローチャートを出力させて、

そのフローチャートを大まかにくくってプログラムのフローを示す図を作った。

goto文を使っていても、if文とelse文の間が数百行と離れていても、

大まかなフローとプログラムの行数との関連が付けば理解はしやすくなる。


ある程度のまとまりで関数としてくくり出されていればこんなことには……

それはswitch文の中のgoto文を見てもわかるけど、

あの例だったらこういう書き方でもいいんですよね。

switch(mode){
   case MODE1:
     exec1();
     exec4();
     break;
   case MODE2:
     exec2();
     exec4();
     break;
   case MODE3:
     exec3();
     exec4();
     break;

問題はexec4();にあたる部分が100行ぐらいあることであり。


今までの仕事で触っていたプログラムはちゃんと構造化プログラミングしてたなぁと。

ループで使われるbreak文、continue文、あるいはプログラム途中でのreturn文は厳密に構造化プログラミングではないのだけど。

ただ、これらはむしろ理解しやすくするものと一般的には理解されているのだし。

ActivityPubはなにものか?

先日、Twitterで一時的に厳しい閲覧数の制限が行われた。

現在はだいぶ緩和されたようだが、なくなったわけではない。

長らくAPI制限や広告の回避手段として使われていたTweetDeckも有料会員限りとなり。

そうはいってもなかなか有料会員が増えている話も聞かないのが実情である。


そんな中でMeta社がThreadsという新しいサービスを始めた。

同社の運営するInstagramを文字だけでも利用できるようなサービスらしい。

といっても、Instagramとアカウントは共通でも、投稿内容は別立てだが。

そして、このThreadsは今後、ActivityPubに対応しMastodonなどのfediverseプラットフォームと接続できるようになると記載がある。

まだ実現されてはいないがそのように宣言されている。


というわけでActivityPubの話である。

さっきfediverseという言葉が出てきたがfederation+universeを表す言葉で、

これも正直よくわかんない言葉なのだが、分散型SNSとほぼ同義である。

Webサービス同士を相互接続することによりサービスの枠を超えてコミュニケーションが取れる仕組みを表している。

これを実現するためのシステムとして中心になっているのがActivityPubだと。

というわけでちょっと実験してみた。


ActivityPubに対応したシステムとしてはMastodonとMisskeyがよく知られている。

MastodonもMisskeyもシステムの名前でそれを使ったサービスは多数ある。

そんな中で僕はPawooというMastodonのインスタンスに登録した。

Pawooは2017年にPixivにより開設され、現在は別会社に譲渡されている。

イラスト投稿サイトのPixivとの関係から絵の投稿が盛んである。

絵の投稿が多く、その内容についてタブーが少ないがために、他のMastodonインスタンスから「鎖国」されるという事件もあった。

その自由度の高さからTwitterで凍結されたユーザーが集まったりしていたとか。

最近はそこまで人気はないかもしれないが、肌には合う気がする。


そのPawooだが、他のActivityPubを採用したサービスのユーザーをフォローできる。

misskey.io にアカウントを持っている知り合いがいたのでフォローしてみたが、

ユーザー検索で @xxxxxxx@misskey.io のように検索してフォローボタンを押すだけ。

ActivityPubは新規に追加された投稿などを送信する仕組みである。

なので他のサービスでの投稿は最近受信したものだけがPawooで表示される。

過去の投稿については投稿者の利用しているサイトで見る必要がある。

投稿に対して返信したり、ブースト(TwitterのReTweetと同じ意味)したり、お気に入りに入れたり出来る。

サービスの垣根を越えて通知・拡散できる仕組みである。


もっともMisskeyの場合、任意の絵文字でレスポンスができるが、Mastodonでは1種類しかないので、

Misskeyでどの絵文字を付けてもMastodonでは同じお気に入りにしか見えないし、

Mastodonでお気に入りにすると、Misskeyではハートマークに変換して表示される。

Misskey同士であれば絵文字を使ったコミュニケーションは通じるが、ActivityPubとして一般に通じるものではない。


ActivityPubに対応したサービスを自分で作ることも可能である。

MastodonやMisskeyをダウンロードして自分のサーバーにインストールできるし、

それ以外の仕組みも考えられて、例えばWordPressのActivityPubプラグインなんてのもある。

これを使えばWordPressの更新内容をフォロワーのタイムラインに流せると。

試してみたが、ちょっと難しい面はあるのだが、確かにできた。

ActivityPub対応のサービスを自営することで特定のサービスに依存しない情報発信ができる。

公的機関などが使う可能性もあるかもしれない。


ただ、一方でこのような仕組みを金に出来るかというのは疑問もある。

Twitterが収益性という面でずっと課題を抱えているというのは知られているが、

それでもTwitterは今起きている様々なことが一箇所に集まることに価値があった。

そのような場だからこそ企業・公的機関の情報発信などに役立てられてきたわけである。

Twitter依存への反省から分散型SNSの流れが出てきたわけだが、分散してはTwitterが持っていたような一箇所に集まることの価値はない。


そんな中でMeta社のThreadsは何を狙っているのかということである。

今はInstagramの投稿を見るためにはInstagramのサイトで見ることになり、

そうすると広告であったりフォローしていない人の投稿も混ざって見せられる。

この構造はThreadも似たようなものだという。

今後ThreadsがActivityPubに対応すれば、Threadsの投稿はThreadsにアクセスせずとも見られるようになる。

逆にThreadsの利用者がThreads以外の投稿を見ることもできるわけだが。

単純には言えないが、Threadsにとって通信リソースばかり食って得るものがないという結果も想定されるところである。

これではMeta社にとっては面白くないので、何らかThreadsへの囲い込みを図るのではないか。

そしたらfediverseというお題目はないがしろにされるのではないか? という懸念はある。


あと、Twitterと比べてMastodon、Misskey、Threadsで共通して弱いのが検索機能である。

これらのサービスの検索はタグ検索しか備えていない。(Threadsは投稿内容の検索機能自体がまだない)

Twitterであれば言葉を調べて、それについてどういう話題があるか見ることができる。

Twitterには世界中の今起きていることが蓄積されているのでとても意味が大きい。

そもそも分散型SNSはサービスごとに投稿データは違うので全てを検索はできない。

(他サービスから受信した投稿データも検索には含まれるとはいえ)

その上で投稿に付けられたタグをもとにした検索しかサポートしないことが多い。

ここはやっぱりTwitterが圧倒的なんだよなと思う。


というわけでやはりTwitterは他に代えがたいというのが実情である。

ただ、ActivityPubという技術自体は面白いところはあるし、

例えばこれでInstagramの投稿をPawooに流せるとかなればそれはそれでうれしい。

問題はそれが金になりそうなビジョンがないということである。

Meta社が金にならないことをやるとは思えませんから何かあるんでしょう。

RHELのライバル対策?

話題になっていたのですが、Red Hat社はRed Hat Enterprise Linux(RHEL)のソースコードについて、一般向けの公開を停止するとのこと。

今後は契約者が申し出た場合に限り公開されることになる。

これがいろいろ波紋を広げているところである。


Linuxのディストリビューションは主に Debian・RedHat・Slackware の系統がある。

この中でRedHat系というのは有償サポートが受けられるRHELの存在というのがとても大きい。

単にLinuxを利用するだけなら無償で利用できる方法はいろいろあるが、

業務用途では保守サービスを長期にわたって受けられることには価値がある。

かつては2003年まではRed Hat Linuxそのものの無償版が存在したが、

RedHat社自身はRHELの有償提供を行い、一方でFedora Projectの支援に回った。

Fedoraは将来のRHELで使用する技術を検討する場としての側面もある。


ただ、実際のところは無償版Red Hat Linuxの代替として多く使われたのはCentOSだった。

CentOSはRHELのソースコードから商標に関わる部分など手を入れたもので、

RHELと高い互換性がある……というかほぼ無償版RHELである。

当初はRed Hat社から独立したプロジェクトだったが、2014年からRed Hat自身が関与するようになっている。

なぜRed Hat社は有償提供のRHELのソースコードを無償公開してきたのか。

これはLinuxカーネルを含む一連のソフトウェアに適用されるGPLの規定による。

GPLが適用されるソフトウェアに手を加えて配布した場合、要求があればそのソースコードを公開しなければならないという規定がある。

この規定はオープンソースソフトウェア(OSS)に利用者にコミュニティへの貢献を求めるものである。

従来、Red Hat社はOSSを利用してRHELを作る代わり、RHELのために手を加えたソースコードを一般に公開することでこの規定を満たしてきた。


2021年にRed Hat社は従来のCentOSの公開を終了し、CentOS Streamを公開することを決定した。

CentOS StreamはRHELのアップストリーム(先行版)に位置づけられる。

ソースコードが反映される順番が RHEL→CentOS から CentOS Stream→RHEL に変わるということである。

ただ、これはCentOS StreamがRHELのBata版という意味ではないとされている。

すぐ次のRHELがCentOS Streamとして公開されているということで、

RHELとほぼ同等の信頼性を備えるものと考えてよい。


この件の受け止め方はいろいろあるのだが、

僕は従来のCentOSをCentOS Streamで代替するのが最適と考えた。

CentOS Streamは仕組みが変わってもRHELとの互換性が高いこと。

従来のCentOSでの経験や、RHELを想定した情報が利用できること。

CentOS StreamはRHELの開発と関連付けることで持続可能性が高まったこと。

このことから現在、このサーバーではCentOS Stream 8を使用している。


ただ、全員がこのような判断をしたわけではない。

そもそもRedHat系を見捨ててDebian系に移行するのは別として――

1つはRHELに移行するという方法。

有償契約というのもあるが、一定の条件を満たせば無償利用ができる。

CentOS Streamにはマイナーバージョンの表記がないのだが、

これは最新の開発状況に合わせた最新版だけが存在しているためである。

指定のマイナーバージョンに固定しなければならない用途ではCentOS StreamはCentOSの代替にならないと。

従来のCentOSはRHEL導入前の評価目的で使われることもあったので、

条件付きで無償利用を認め、本格的に使うなら有償利用にしてねと。

このような選択肢もRed Hat社は示したわけである。


そしてもう1つ言われたのがCentOS以外のRHEL派生ディストリビューションに移行するという方法である。

当時はまだRHELのソースコードは無償配布されていた。

なので今後も従来のCentOSみたいなものを作れると思っていたわけである。

主に名前が挙げられていたのが AlmaLinux、Rocky Linux、Oracle Linux、MIRACLE Linuxといったところ。

AlmaLinuxは従来のCentOSの趣旨に最も近いものだと有力視されたらしい。

当初のCentOSはRedHatとは独立したプロジェクトだったことを考えれば、原点回帰とも言えるものである。


ところがRedHat社はRHELのソースコードの一般公開を止めてしまった。

GPLの規定ではプログラムを利用できる人から要求があればソースコードを公開すればよいので、必ずしも一般に公開しなくてもよい。

問題はこのソースコードの使い方について契約上の制約があるということ。

Red HatがクローンOSベンダを非難、「付加価値もなくコードをリビルドするだけなら、それはオープンソースに対する脅威だ」と (PublicKey)

RHELのサブスクリプション契約で再配布を禁止する規定がある。

この規定により入手したソースコードをそのまま使ってLinuxディストリビューションを作ることは契約違反となる。


これは実態としてGPLの規定を死文化させるものではないかと批判はある。

最新バージョンのRHELのアップストリームにはCentOS Streamがあり、

CentOS Streamを無償公開することでRedHat社がOSSに手を加えた成果はほとんど公開されることとなる。

では、Red Hat社はRHELのなにを利用されたくないのか?

それはマイナーバージョンごとの長期間のメンテナンス活動の成果ではないかと言われている。


さっき「CentOS以外のRHEL派生ディストリビューション」という話を書いた。

実はこの中には大手のベンダーが関わって、なおかつ有償サポートを提供するものが多いのである。

AlmaLinuxはCloudLinux、Oracle LinuxはOracleが有償サポートを提供している。

MIRACLE LINUXを提供しているサイバートラスト社は次期バージョンからAlmaLinuxの日本国内での有償サポート提供に切り替えると言っている。

Rocky LinuxもCIQ社が有償サポートを契約し、Google Cloudと提携関係にある。

これらの取り組みはクラウドコンピューティングとも関係があるようだ。


Red Hat社は長期にわたってサポートを必要とする人は有償利用と考えてきて、

かつてはそれは価値があるものとして受け入れられてきた。

それだけLinuxの業務利用について、Red Hat社の存在は圧倒的だったと。

しかし、RHELのソースコードをほぼそのまま転用して商売する会社がいくつも出現し、

さすがにこれは無視できないとなった結果が冒頭の話なのではないか。

Red Hat社が今後もRHEL開発を通じてOSSに貢献するには必要な策だったと言われると納得感はある。


CentOS Streamで公開されているコードを利用していけば、

RHELと互換性のあるディストリビューションは維持できる可能性がある。

ただ、それはそれで労力がかかるので、それが維持し続けられるかはわからない。

短期的には維持できても、長期的に維持できるかはわからない。

RHELとの互換性を保ちながら性能強化を図ったOracle Linuxは、

単なるRHELのコピーではないから続けるモチベーションはありそうだが、

RHELとの互換性を保つことが段々難しくなることは考えないといけない。


CentOS Streamは持続可能であるということを前提としているが、

あまりに行きすぎるとその状況すら怪しくなってくる。

そうならないことといいんだけど……

リアルタイムOSを使う意味

ここ最近、今までの担当製品と別の製品の仕事をしている。

一時的な話だし、相変わらず担当製品の仕事もちょこちょこあるんだけど。

物を触る方が先かなと思ったけど、先に設計を見てからの方がいいか、

と、ドキュメントを見るもピンと来ないので、ソースコードを見るが書いてあることとの対応関係がさっぱりわからん。

というわけでしばらくはソースコードの解読に注力していたが、

その甲斐もあって大まかな構造が理解できて、ドキュメントも読めるようになってきた。


今まで触ってきた製品のプログラムと、この製品のプログラム、

最も大きな違いがリアルタイムOSを使っているということである。

今まで触っていた製品は全部OSなしだったんですよね。

ただ、フタを開けてみると意外とシンプルな構造だった。

優先順位に従ってタスクスケジューリングをやらせているぐらいだった。

いろいろな都合があるのかドライバ部以外にもハードウェア依存の動作が散らばっていたり、なかなかな構成である。


今までの製品がなぜOSなしで問題なかったのか?

と考えてみると、実行するべき処理の増減が少ないというのはあったのかも。

処理量が増えたので、優先度の低い処理は遅らせて、優先度の高い処理を規定時間内に確実に終わらせるようにするとか。

そういうスケジューリングが求められることがなかったと。

一方でこれから担当する製品というのは、複数タイプの処理量が様々増減する。

パフォーマンスが許す範囲で様々な組み合わせが考えられる。

これらのリソース配分をOSにやらせるのは理にかなっているなとは思った。


ただ、もしかするとOSがあったら実現方法が変わってたかもと思うところはあり、

それがシリアル通信と他の処理を並列に実行する仕組みである。

通信開始時にはペリフェラルの操作を行う必要があるが、

そこから実際に送受信している時間というのは他のプログラムを実行できる。

そして送受信が完了すると割り込みで通知を受けて、次の通信開始処理をすると。

当初、通信データ準備→1つ目の通信開始→各種処理→送受信完了割込で2つ目の通信開始→元の処理に戻る……ということをやっていたそう。

しかし、その後、さらに通信量が増えてしまいこれでは収まらなくなり、

通信データ準備と並行して数個の通信をやることにしたそうである。

こういう問題はOSのスケジューラを適切に使えば打開できたかもしれない。


こうして構造が理解できてくると今度困るのはアルゴリズムが複雑すぎること。

ドキュメントに書かれている処理内容に対してアルゴリズムが複雑すぎるし、

その意図が理解できる図表がほとんどないのが困ったところである。

このままでは手を入れたり、デバッグするのも大変である。

手を入れずに済むならそのまま行く方が安全だが、デバッグ出来ないとなればこれはまた問題である。どうしたものか。


実はこの仕事に入ることになった背景として、

元々担当していた人が社内の他の職場に異動になってしまったという事情がある。

以前より担当している人は1人だけいるのだが、1人ではいろいろ厳しい。

チーム内で分担しようにも候補となるメンバーは近年配属された2人。

そこで従来からの担当者の業務を分散しながら、他メンバーへの技術伝承を行うということが求められている。

これを実現するためには相当にシステムの理解を深めなければいけない。

ぶっちゃけ今の担当者にとっても不明点だらけらしいんですよね。

リーダーには「ほとんどリバースエンジニアリングだな」と言われたが、そうなりそうですね。

追加ディスクをくっつけて容量拡張

朝起きるとPostfixでエラー発生の通知が多数届いていて、

“Insufficient system storage”ってなんだ? と思ったらディスク容量が足りないらしい。

調べてみると確かに / の容量を100%まで食い潰していた。


取り急ぎなんとかする必要があるとフォルダ容量を調べて下記3つの対策をした。

  1. 個人用のデータ保管庫のうちほぼ使っていなくて復元可能なデータを削除
  2. メールボックスの迷惑メールフォルダの中身を削除
  3. MySQLのログファイルの容量を削減 (innodb_log_file_sizeの設定変更)

2.はあんまり効かなかったね。でも、これで10%以上の余裕は確保できた。


おそらくトドメを刺したのはメールかMySQLだと思うのだが、

容量を圧迫する要因が個人用のデータ保管庫ですね。

今回、ほぼ使っていないデータは消したのだが、今後追加の予定もあった。

でも、このVPSで使える容量に対してはだいぶ余裕があったような。

調べてみると、VPSで使えるストレージ容量は100GBなのだが、

実際にシステムで使える容量は17GBほどとだいぶ少ない。


この原因はお名前.com VPSのストレージが「基本ディスク」と「追加ディスク」に分かれていることだった。

あらかじめ設定しておけば契約容量を自由に割り振ることができるのだが、

初期設定では基本ディスクが20GB、残り(本契約では80GB)が追加ディスクという扱いになる。

これをあらかじめ基本ディスク100GBにしておけばこんな問題はなかったのだが。

サイズ変更はできるのだが、サイズを縮小する方のディスクが吹き飛ぶなど、

操作ミスに対するリスクが高いのでやりたくないなぁと。


確認したところ、基本ディスクは /dev/vda 、追加ディスクは /dev/vdb で、

ディスクは分かれているが、現在のままでもちゃんと100GB使えるようだ。

追加ディスクに新しくパーティションを切ってマウントすれば……

とも思ったが、LVMでは複数ディスクを合算して使うことができたよねと。

調べたらちゃんとできそうなのでやってみることにした。


まずLVMの用語を確認する。

物理的なディスクにパーティションを切ったものをPhysical Volume(PV)と呼ぶ。

次にPVを1個以上組み合わせたVolume Group(VG)を作る。

現在は1つのPVから構成されるVGがある状態になっている。

VGを適宜分けてLogical Volume(LV)を作成する。

このLVには物理ディスクに切られたパーティションのようにファイルシステムを作ることができる。

現状は2つのLVがあって、1つがスワップ領域、もう1つがXFSのファイルシステムで、ルートディレクトリに割りあてられている。


というわけで、まずは追加ディスクにPVを作成する。

そして、このPVを既存のVGに追加して、VGを拡張する。

VGを拡張した分、LVを拡張して、ファイルシステムを拡張すると、

基本ディスク・追加ディスクの構成を変えずにメインで使っているファイルシステムを拡張できるというわけである。


まず、追加ディスクにパーティションを作成する。

# fdisk /dev/vdb

Hex codeで”8e”とするとLVMになる。全領域をLVMにしてしまう。

次にこのパーティションをPVにする。

# pvcreate /dev/vdb1

pvdisplayコマンドでPVの状況を確認出来る。

基本ディスクのPVがあって、追加ディスクのPVが”NEW Physical volume”と表示されている。

VGの状況はvgdisplayコマンドで確認出来る。

これを見ると基本ディスクのPVで構成される”cs_gmo2”というVGがあるので、

# vgextend cs_gmo2 /dev/vdb1

で、新しく作成したPVを既存のVGに加える。

LVの状況もlvdisplayコマンドで確認出来る。

ファイルシステムの方は /dev/cs_gmo2/root という名前で、これを拡張したいので、

# lvextend -l +100%FREE /dev/cs_gmo2/root

で、当該VGの未使用領域全部をこのLVの領域拡張に充てる。

最後にファイルシステムの容量も拡張する。

# xfs_growfs /

マウント先が/のXFSを拡張する場合はこう書くらしい。


これでVPSのストレージ容量がフルに使えるようになった。

最初から基本ディスクに割りあてておけばこんなことにはならなかったが、

後から気づいてもほぼ同じ状態にすることができたのでよいということで。

これらの作業は動作中にすることもできるので安心である。


それにしてもなんでこんな仕様なんだろうね?

なにか歴史的な経緯でもあるんだろうか?

他社を見ると、ストレージを追加購入できるような場合はともかく、

標準装備のストレージを基本・追加と分ける構成は独特に見える。

新規申込みの人は基本ディスクに100%からスタートにしておけばいいのにとか思いますけどね。

急速充電の効果はどんなもの?

Redmi Padの高速充電はQuickCharge 3.0相当という話を書いたが、

家ではUSB PDの充電器とは別に付属品の充電器を設置したからよいとして。

出先での急速充電を1台で行うためにUSB PD・QuickCharge 3.0両対応の充電器を購入した。


大手のメーカーも出してないわけではないのだが……

Anker PowerPort Atom III (Two Ports)

USB PD対応 AC充電器(USB PD45W・QC + 12W/C×1+A×1) (ELECOM)

出力が大きいということもあり携帯用には大きいなと。

いろいろ探したところ一方のみ使用時18W出力でコンパクトなものがあった。

メーカー名は判然としないが(輸入業者の名前でPSEマークが付けられていた)、

これでスマートフォン・タブレットともども最高速度で充電ができるからいいねと。

Type-CとType-A両方接続すると双方とも5V出力になるらしいが、そういう使い方をする予定はない。


USB PDやQuickChargeによる急速充電は確かに速いのだが、

実際の使い方にとってその差を実感出来るかというと案外難しい。

というので、AQUOS sense6とRedmi Padでそれぞれ50%から満充電にしたときのデータから検討してみた。

従来方式のUSB BC(5V×1.5A)相当と急速充電で充電が5%進むのにかかる時間を拾ってグラフを描く。


そしてグラフを観察するとこんな感じだった。

  • AQUOSのUSB PDでは75%あたりまで直線的でそこから充電ペースが落ちる
  • AQUOSのUSB BCでは80%あたりまで直線的でそこから充電ペースが落ちる
  • Redmi PadのQuickChargeは80%まで直線的で、そこから充電ペースが落ちる
  • Redmi PadのUSB BCは100%まで直線的に充電が進む

AQUOSはパッテリー温度も見ながら充電しているなどそう単純ではないが、

ある程度までは直線的に充電が進む前提でシミュレーションしてみる。


充電開始時の電池残量と充電時間により効果は違う。

AQUOS sense6で電池残量10%から95%までの充電時間を見ると、

USB BCで150分に対して、USB PDで102分で48分短縮と効果が大きい。

ただ、そこまで電池残量を減らして充電器に付けるのは稀だと思う。

20%からは42分短縮、30%から34分短縮、40%から27分短縮、50%から21分短縮、60%から14分短縮、70%から8分短縮、80%から3分短縮。

普段は60~70%ぐらいで充電器に付けることが多いから、10分程度の短縮効果しかない。

AQUOSが電池の長寿命化のために充電ペースを落としてしまうからだけど。

ただ、旅行のときなど40%程度まで減らして付けることはあるから、そしたら30分ほど短縮で効果はありそうな気がする。


もう1つの観点が充電器に取り付ける時間だよね。

50%からスタートして20分後にPD73%・BC63%、30分後にPD80%・BC69%、

PDだとこれぐらいの時間であらかた充電できるので効果が見えやすい。

ただ、45分後にPD88%・BC79%、60分後にPD93%・BC86%というと大した差はない。

開始時の電池残量にもよるのだが、30分以内の充電だと効果が見えやすい。

在宅時はスマートフォンは定位置で充電している時間が長く、

ということは充電時間は30分よりはるかに長く、効果は見えにくそうだ。


一方のタブレットPCは在宅時に充電器から外して使う時間が長い。

さらに電池容量が大きいので、こちらは急速充電の効果が見えやすい。

残量10%から95%までの充電時間はUSB BC340分に対して、QC138分と202分短縮、

さすがにそこまで電池を使い尽くして充電開始にすることは稀としても、

残量30%から152分短縮、50%から119分短縮、60%から77分短縮、70%から52分短縮、80%から27分短縮と。

60~70%まで減らせば1時間も充電時間が変わるのだから大きい。

充電時間ごとの効果も60%から充電を開始して、

30分後にBC67%・QC80%、60分後にBC75%・QC94%といずれも効果大。

30分程度の充電で他用途で使うこともけっこうありますからね。


じゃあ、自宅にUSB PDの充電器いらんのではという話もありますが。

ただ、充電忘れてた時に30分程度の充電をすることも時々あるからね。

そもそも元はHUAWEIのタブレットがUSB PD対応していたのだから、

タブレットでの恩恵が大きかったわけですからね。


一方で旅行ということになれば急速充電の効果はおしなべて大きい。

  • スマートフォンを電池残量40%以下から充電開始
  • スマートフォンを30分程度充電してから外出
  • タブレットを1時間程度充電して、スマートフォンの充電に切り替え

なんていう使い方は普通に発生しますからね。

こういうニーズに1台で対応できるコンパクトな充電器はメリットが大きい。


このあたりは人によってもいろいろだと思うけどね。

世間的に見れば、在宅時でもスマートフォンを多用する人は多い。

そういう場合、30分程度の充電の効果が大きいことはメリットになる。

その逆に充電する機器数が多すぎる場合、口数が多い充電器を使いたいということで、

こうすると個別に電圧制御が必要な急速充電対応のものは選びにくいかもしれない。

Anker PowerPort 6

出力電圧5V固定だから口数を増やしやすい。

多くの機器を同時充電できるなら1つ1つは遅くてもよいという考えもあるかもしれない。


世の中、まだまだUSB BCでの充電が普通に行われているのだと思うし、

案外それでもなんとかなるのかもしれない。

今はだいぶ改善したけど、USB PDの充電に使うケーブルは割高である。

両側Type-CならばUSB 2.0でよいが、これが案外高くて入手性が悪いと。

ただ、大容量バッテリーを積んでいるタブレットだときついですね。

これはやっぱりQuickCharge対応の充電器が出先でも必要ですね。