JavaScriptを有効にしてください

Lineage OSで任意のアプリにAux Cameraを使用させる

 ·   ·  ☕ 5 分で読めます

注意

この記事では、LineageOS19.1の環境下でAux Cameraを任意のアプリに対して開放するというスマホとしても、Androidとしても、アプリの用途としても通常用途とは明らかに外れている用法を扱っています。
LineageベースのカスタムROMでは長時間動作させても端末に問題は発生しないことを確認していますが、実際に使用する際は自己責任でお願いします。

あらすじ

きっかけはvdo.ninjaでスマホに搭載されている広角レンズの映像をストリームしたいと思ったことが始まりでした。
vdo.ninjaを用いて配信を行うには大きく分けて方法が2つあり、任意のブラウザーを用いる方法と、flutter製のネイティブアプリを用いる方法の2つがあります。
ネイティブアプリの方は内カメラ・外カメラの切り替えすらもうまく行かなかったので断念しましたが(まだベータ版のようですので今後に期待しています)、Android版Google Chromeなら任意のカメラを表示してくれそうな気配がします。
しかし、実際にやってみると以下のように2つのカメラしか表示されません。

There’s only two cams

しかし、上記の画像にはcamera2と記載されています。
頑張れば表示できそうなので、詳しく調べることにしました。

調査

アプリ側からのカメラの制御部分は、androidのframeworkが担っています。
他のカスタムOSやAOSP、メーカー独自実装などではどうなっているか確認していませんが、今回私はLineageOSベースのカスタムOSを使用しているので、LineageOS/android_frameworks_baseを参照してみます。
GitHubの検索機能を使い軽く調べたところ、core/java/android/hardware/Camera.java気になる記述を発見しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public static boolean shouldExposeAuxCamera() {
    /**
     * Force to expose only two cameras
     * if the package name does not falls in this bucket
     */
    String packageName = ActivityThread.currentOpPackageName();
    List<String> packageList = Arrays.asList(
            SystemProperties.get("vendor.camera.aux.packagelist", packageName).split(","));
    List<String> packageExcludelist = Arrays.asList(
            SystemProperties.get("vendor.camera.aux.packageexcludelist", "").split(","));


    return packageList.contains(packageName) && !packageExcludelist.contains(packageName);
}

注意: ここから先の記述はソースコードを読んだ筆者による想像です。

この記述によって、vendor.camera.aux.packagelistというシステムプロパティにパッケージ名が含まれており、かつvendor.camera.aux.packagelistにパッケージ名が含まれていない場合のみAux Cameraが開放されるという仕組みになっているようです。

Androidでは一般的にカメラID0がバックのメインカメラ、1がフロントのメインカメラ、その後に所謂Aux Cameraと呼ばれているスマホによって搭載されていたりいなかったりする広角・接写レンズ等が続きます。
このshouldExposeAuxCamera()別の関数getNumberOfCameras()などによって呼ばれています。

1
2
3
4
5
6
7
public static int getNumberOfCameras() {
    int numberOfCameras = _getNumberOfCameras();
    if (!shouldExposeAuxCamera() && numberOfCameras > 2) {
        numberOfCameras = 2;
    }
    return numberOfCameras;
}

このように、カメラを先頭から2つしか見せない、つまりバックメイン、フロントメインしかないかのように見せかけることによって2つ以上のカメラの搭載を想定していないアプリとの互換性を確保している、ということなのだと思います。
しかし全く使えないのでは困るので、ホワイトリスト・ブラックリストを利用して必要なアプリ(カメラアプリが想定されているのだと思います)のみ開放する、といった処理をしているのでしょう。

実践

話が分かればあとは簡単です。
実際にpropsを見てみましょう。

1
2
getprop vendor.camera.aux.packagelist
# org.codeaurora.snapcam,com.android.camera
1
2
getprop vendor.camera.aux.packageexcludelist
# (出力なし)

この中身を空にすれば全てのアプリにAux Cameraが開放されます。
が、流石にそれだと困ってしまうので(一部起動しただけでクラッシュするアプリがあるので全開放で常用はおすすめしません)、適切なアプリを指定してあげましょう。

注意: Androidのpropsには91byteの長さ制限があります。パッケージを3個以上など大量に詰め込むと文字数を簡単にオーバーします。回避したい場合、ブラックリスト等の活用を検討してください。

1
setprop vendor.camera.aux.packagelist com.android.chrome

Aux on Chrome

私の場合は8つの選択肢が表示されていますが、実際はカメラは4つしかありません。
その他の選択肢を選ぼうとすると、Chromeがクラッシュします。(そもそも特殊なカメラを普通のカメラのように読み込もようとしているので当たり前といえば当たり前な気もします)
しかしながら、適切な選択肢を選べばその後の動作に支障はないため、これで目的は達成されたと言って良いと思います。

永続化

setpropで設定したpropsは再起動すると消えてしまうため、用途によっては永続化を行う必要があります。
方法はたくさんありますが、今回は2つ紹介します。
いずれの方法も、編集後は再起動を行って反映を確認してください。

1. build.propsに直接書き込む

systemパーティション直下にあるbuild.propsに直接変更を書き加えてしまう方法です。
簡単ですが、systemlessな方法ではないので、safetynet等の改造検知ソリューションと相性が悪いかもしれません(未確認)。
ファイルに以下のように必要なパッケージを書き加えるだけですが、すでに項目が存在している場合もあるため注意してください

vendor.camera.aux.packagelist=com.android.chrome

2. Magisk Moduleを作る

こちらの方がSystemlessでMagiskをお使いの場合はベストな選択肢だと思います。
Magiskにはモジュール直下のsystem.propをシステムプロパティとして読み込む機能があるため、新しくモジュールを作成するなり他のモジュールに寄生させるなどしてsystem.propを作成します。
内容はbuild.propsの項と同じく以下のようなpropを記述したものになります。

vendor.camera.aux.packagelist=com.android.chrome

正しくロードされていれば、loading [system.prop]と表示されpropの値が変化しているはずです。

共有

hayabusa2yk
著者
hayabusa2yk
Dev/Admin of servers