データ blob を使用した大規模データセットの安全な共有

機械学習やメディア再生が関係するような状況では、1 つの大規模データセットをアプリが別のアプリと共用したい場合があります。

Android 11(API レベル 30)では、ネットワーク上とディスク上の両方でデータの冗長性を軽減するために、機械学習やメディア再生のようなユースケースに対応する共有データセットがキャッシュに保存されます。こうした大規模な共有データセットにアプリがアクセスする必要がある場合、新しいコピーをダウンロードするかどうかを判断する前に、「共有データ blob」と呼ばれる、このキャッシュに保存されたデータセットをまず探すことができます。アプリでは、Android 11 の新しいシステム サービス マネージャーである BlobStoreManager の API を通じて、この共有データセット機能を使用できます。

システムが共有データ blob を保持し、どのアプリがそれにアクセスできるかを管理します。アプリがデータ blob を提供する際、以下のいずれかのメソッドを呼び出して、他にどのアプリがアクセス権を持つかを指定できます。

  • デバイス上の特定のアプリのセットにアクセス権を付与するには、それらのアプリのパッケージ名を allowPackageAccess() に渡します。
  • 自分のアプリに使用する鍵と同じ鍵で署名された証明書を持つアプリ(自分が管理するアプリスイートなど)にのみアクセスを許可する場合は、allowSameSignatureAccess() を呼び出します。
  • デバイス上のすべてのアプリにアクセス権を付与するには、allowPublicAccess() を呼び出します。

共有データ blob にアクセスする

システムは各共有データ blob を BlobHandle オブジェクトを使って表します。BlobHandle の各インスタンスには、暗号化されて安全なハッシュと、そのデータセットを識別できるなんらかの詳細情報が含まれます。

共有データ blob にアクセスするには、サーバーから識別情報をダウンロードします。この情報を使って、データセットがシステムですでに利用可能かどうかを確認します。

次のステップは、データが利用可能かどうかによって異なります。

データセットが利用できる

データセットがそのデバイス上ですでに利用できる場合は、次のコード スニペットに示すように、システムからアクセスします。

Kotlin

val blobStoreManager =
        getSystemService(Context.BLOB_STORE_SERVICE) as BlobStoreManager
// The label "Sample photos" is visible to the user.
val blobHandle = BlobHandle.createWithSha256(sha256DigestBytes,
        "Sample photos",
        System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1),
        "photoTrainingDataset")
try {
    val input = ParcelFileDescriptor.AutoCloseInputStream(
            blobStoreManager.openBlob(blobHandle))
    useDataset(input)
}

Java

BlobStoreManager blobStoreManager =
        ((BlobStoreManager) getSystemService(Context.BLOB_STORE_SERVICE));
if (blobStoreManager != null) {
    // The label "Sample photos" is visible to the user.
    BlobHandle blobHandle = BlobHandle.createWithSha256(
            sha256DigestBytes,
            "Sample photos",
            System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1),
            "photoTrainingDataset");
    try (InputStream input = new ParcelFileDescriptor.AutoCloseInputStream(
            blobStoreManager.openBlob(blobHandle))) {
        useDataset(input);
    }
}

データセットが利用できない

データセットが利用できない場合は、次のコード スニペットに示すように、サーバーからデータセットをダウンロードして、システムに提供します。

Kotlin

val sessionId = blobStoreManager.createSession(blobHandle)
try {
    val session = blobStoreManager.openSession(sessionId)
    try {
        // For this example, write 200 MiB at the beginning of the file.
        val output = ParcelFileDescriptor.AutoCloseOutputStream(
                session.openWrite(0, 1024 * 1024 * 200))
        writeDataset(output)

        session.apply {
            allowSameSignatureAccess()
            allowPackageAccess(your-app-package,
                    app-certificate)
            allowPackageAccess(some-other-app-package,
                    app-certificate)
            commit(mainExecutor, callback)
        }
    }
}

Java

long sessionId = blobStoreManager.createSession(blobHandle);
try (BlobStoreManager.Session session =
        blobStoreManager.openSession(sessionId)) {
    // For this example, write 200 MiB at the beginning of the file.
    try (OutputStream output = new ParcelFileDescriptor.AutoCloseOutputStream(
            session.openWrite(0, 1024 * 1024 * 200)))
        writeDataset(output);
        session.allowSameSignatureAccess();
        session.allowPackageAccess(your-app-package,
                    app-certificate);
        session.allowPackageAccess(some-other-app-package,
                    app-certificate);
        session.commit(getMainExecutor(), callback);
    }
}