diff --git a/vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/BundleKeys.java b/vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/BundleKeys.java index 8293f8035..0abba2f3b 100644 --- a/vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/BundleKeys.java +++ b/vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/BundleKeys.java @@ -47,8 +47,8 @@ public final class BundleKeys { public static PackKey> SLICE_IDS = new PackKey.StringArrayList("slice_ids"); public static SliceKey> CHUNK_INTENTS = new SliceKey.ParcelableArrayList<>("chunk_intents", Intent.class); - public static SliceKey COMPRESSION_FORMAT = new SliceKey.Int("compression_format"); - public static SliceKey PATCH_FORMAT = new SliceKey.Int("patch_format"); + public static SliceKey<@CompressionFormat Integer> COMPRESSION_FORMAT = new SliceKey.Int("compression_format"); + public static SliceKey<@PatchFormat Integer> PATCH_FORMAT = new SliceKey.Int("patch_format"); public static SliceKey UNCOMPRESSED_HASH_SHA256 = new SliceKey.String("uncompressed_hash_sha256"); public static SliceKey UNCOMPRESSED_SIZE = new SliceKey.Long("uncompressed_size"); diff --git a/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/AssetModuleService.kt b/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/AssetModuleService.kt index 02e90a84f..cde513190 100644 --- a/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/AssetModuleService.kt +++ b/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/AssetModuleService.kt @@ -107,20 +107,20 @@ class AssetModuleServiceImpl( override suspend fun getSessionStates(params: GetSessionStatesParameters, packageName: String, callback: IAssetModuleServiceCallback?) { val listBundleData: MutableList = mutableListOf() - packageName.takeIf { it == packageDownloadData[packageName]?.packageName }?.let { - packageDownloadData[packageName]?.moduleNames?.forEach { moduleName -> - if (moduleName in params.installedAssetModules) return@forEach - listBundleData.add(sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, null, null)) + packageDownloadData[packageName]?.moduleNames?.forEach { moduleName -> + if (moduleName in params.installedAssetModules) return@forEach - packageDownloadData[packageName]?.getModuleData(moduleName)?.chunks?.forEach { chunkData -> - val destination = chunkData.getChunkFile(context) - if (destination.exists() && destination.length() == chunkData.chunkBytesToDownload) { - sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, chunkData, destination) - } + listBundleData.add(sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, null, null)) + + packageDownloadData[packageName]?.getModuleData(moduleName)?.chunks?.forEach { chunkData -> + val destination = chunkData.getChunkFile(context) + if (destination.exists() && destination.length() == chunkData.chunkBytesToDownload) { + sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, chunkData, destination) } } } + Log.d(TAG, "getSessionStates: $listBundleData") callback?.onGetSessionStates(listBundleData) } @@ -165,7 +165,8 @@ class AssetModuleServiceImpl( checkSessionValid(packageName, params.sessionId) // TODO: Implement - throw UnsupportedOperationException() + callback?.onNotifySessionFailed(bundleOf(BundleKeys.SESSION_ID to params.sessionId)) + //throw UnsupportedOperationException() } override suspend fun keepAlive(params: KeepAliveParameters, packageName: String, callback: IAssetModuleServiceCallback?) { @@ -176,13 +177,12 @@ class AssetModuleServiceImpl( override suspend fun getChunkFileDescriptor(params: GetChunkFileDescriptorParameters, packageName: String, callback: IAssetModuleServiceCallback?) { checkSessionValid(packageName, params.sessionId) - val parcelFileDescriptor = runCatching { - val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber) - ParcelFileDescriptor.open(downLoadFile, ParcelFileDescriptor.MODE_READ_ONLY).also { - fileDescriptorMap[downLoadFile] = it - } - }.getOrNull() + val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber) + val parcelFileDescriptor = ParcelFileDescriptor.open(downLoadFile, ParcelFileDescriptor.MODE_READ_ONLY).also { + fileDescriptorMap[downLoadFile] = it + } + Log.d(TAG, "getChunkFileDescriptor -> $parcelFileDescriptor") callback?.onGetChunkFileDescriptor( bundleOf(BundleKeys.CHUNK_FILE_DESCRIPTOR to parcelFileDescriptor), bundleOf(BundleKeys.ERROR_CODE to AssetPackErrorCode.NO_ERROR) @@ -206,6 +206,7 @@ class AssetModuleServiceImpl( } } val bundleData = buildDownloadBundle(packageDownloadData[packageName]!!, params.moduleNames) + Log.d(TAG, "requestDownloadInfo -> $bundleData") callback?.onRequestDownloadInfo(bundleData, bundleData) } @@ -217,6 +218,7 @@ class AssetModuleServiceImpl( override suspend fun cancelDownloads(params: CancelDownloadsParameters, packageName: String, callback: IAssetModuleServiceCallback?) { // TODO: Implement - throw UnsupportedOperationException() + callback?.onCancelDownloads(bundleOf(BundleKeys.ERROR_CODE to AssetPackErrorCode.NO_ERROR)) + //throw UnsupportedOperationException() } } \ No newline at end of file diff --git a/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/DownloadData.kt b/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/DownloadData.kt index 137930242..ccc3f7c33 100644 --- a/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/DownloadData.kt +++ b/vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/DownloadData.kt @@ -7,6 +7,7 @@ package com.google.android.finsky.assetmoduleservice import android.content.Context import com.google.android.finsky.getChunkFile +import com.google.android.play.core.assetpacks.protocol.CompressionFormat import java.io.File import java.io.Serializable @@ -66,6 +67,7 @@ data class ChunkData( val chunkSourceUri: String?, val chunkBytesToDownload: Long, val chunkIndex: Int, + val sliceCompressionFormat: @CompressionFormat Int, val sliceUncompressedSize: Long, val sliceUncompressedHashSha256: String?, val numberOfChunksInSlice: Int diff --git a/vending-app/src/main/kotlin/com/google/android/finsky/extensions.kt b/vending-app/src/main/kotlin/com/google/android/finsky/extensions.kt index ddb3e2049..4a1e53664 100644 --- a/vending-app/src/main/kotlin/com/google/android/finsky/extensions.kt +++ b/vending-app/src/main/kotlin/com/google/android/finsky/extensions.kt @@ -9,6 +9,7 @@ import android.accounts.Account import android.accounts.AccountManager import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle import android.util.Log @@ -19,6 +20,7 @@ import androidx.core.content.pm.PackageInfoCompat import com.android.vending.licensing.AUTH_TOKEN_SCOPE import com.android.vending.licensing.getAuthToken import com.android.vending.licensing.getLicenseRequestHeaders +import com.google.android.finsky.assetmoduleservice.AssetPackException import com.google.android.finsky.assetmoduleservice.DownloadData import com.google.android.finsky.assetmoduleservice.ModuleData import com.google.android.finsky.assetmoduleservice.ChunkData @@ -28,7 +30,6 @@ import com.google.android.play.core.assetpacks.protocol.BroadcastConstants import com.google.android.play.core.assetpacks.protocol.BundleKeys import com.google.android.play.core.assetpacks.protocol.CompressionFormat import com.google.android.play.core.assetpacks.protocol.PatchFormat -import kotlinx.coroutines.runBlocking import org.microg.gms.auth.AuthConstants import org.microg.vending.billing.GServices import org.microg.vending.billing.core.HttpClient @@ -44,7 +45,11 @@ private const val ASSET_MODULE_DELIVERY_URL = "https://play-fe.googleapis.com/fd private const val TAG = "AssetModuleRequest" fun getAppVersionCode(context: Context, packageName: String): Long? { - return runCatching { PackageInfoCompat.getLongVersionCode(context.packageManager.getPackageInfo(packageName, 0)) }.getOrNull() + return try { + PackageInfoCompat.getLongVersionCode(context.packageManager.getPackageInfo(packageName, 0)) + } catch (e: PackageManager.NameNotFoundException) { + throw AssetPackException(AssetPackErrorCode.APP_UNAVAILABLE, e.message) + } } fun Bundle?.get(key: BundleKeys.RootKey): T? = if (this == null) null else BundleKeys.get(this, key) @@ -105,14 +110,12 @@ suspend fun HttpClient.initAssetModuleData( val androidId = GServices.getString(context.contentResolver, "android_id", "0")?.toLong() ?: 1 - val moduleDeliveryInfo = runCatching { - post( - url = ASSET_MODULE_DELIVERY_URL, - headers = getLicenseRequestHeaders(oauthToken, androidId), - payload = requestPayload, - adapter = AssetModuleDeliveryResponse.ADAPTER - ).wrapper?.deliveryInfo - }.getOrNull() + val moduleDeliveryInfo = post( + url = ASSET_MODULE_DELIVERY_URL, + headers = getLicenseRequestHeaders(oauthToken, androidId), + payload = requestPayload, + adapter = AssetModuleDeliveryResponse.ADAPTER + ).wrapper?.deliveryInfo Log.d(TAG, "initAssetModuleData: moduleDeliveryInfo-> $moduleDeliveryInfo") return initModuleDownloadInfo(packageName, appVersionCode, moduleDeliveryInfo) } @@ -187,6 +190,7 @@ private fun initModuleDownloadInfo(packageName: String, appVersionCode: Long?, d chunkSourceUri = dResource.sourceUri, chunkBytesToDownload = dResource.bytesToDownload, chunkIndex = chunkIndex, + sliceCompressionFormat = sliceInfo.fullDownloadInfo.compressionFormat ?: CompressionFormat.UNSPECIFIED, sliceUncompressedSize = uncompressedSize ?: 0, sliceUncompressedHashSha256 = uncompressedHashSha256, numberOfChunksInSlice = numberOfChunks @@ -269,34 +273,26 @@ fun sendBroadcastForExistingFile(context: Context, downloadData: DownloadData, m downloadBundle.put(BundleKeys.PACK_BASE_VERSION, moduleName, packData.moduleVersion) downloadBundle.put(BundleKeys.PACK_VERSION_TAG, moduleName, null) packData.chunks.map { it.copy() }.forEach { - val sliceId = it.sliceId ?: "" - val uncompressedSize = it.sliceUncompressedSize - val uncompressedHashSha256 = it.sliceUncompressedHashSha256 - val numberOfChunksInSlice = it.numberOfChunksInSlice - val chunkIntents: ArrayList - if (destination == null) { - chunkIntents = ArrayList(Collections.nCopies(numberOfChunksInSlice, null)) - } else { - val uFile = Uri.parse(destination.absolutePath).path?.let { path -> File(path) } - chunkIntents = ArrayList(Collections.nCopies(numberOfChunksInSlice, null)) - val uri = Uri.fromFile(uFile) + val sliceId = it.sliceId + val chunkIntents = ArrayList(Collections.nCopies(it.numberOfChunksInSlice, null)) + if (chunkData != null && destination != null) { + val uri = Uri.fromFile(destination) context.grantUriPermission(moduleName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) val intent = Intent(Intent.ACTION_VIEW) intent.setDataAndType(uri, context.contentResolver.getType(uri)) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - val resourceBlockIndex = chunkData?.chunkIndex - if (uFile?.exists() == true && chunkData?.sliceId == sliceId && resourceBlockIndex != null) { - if (chunkIntents[resourceBlockIndex] == null) { - chunkIntents[resourceBlockIndex] = intent + if (destination.exists() && chunkData.moduleName == moduleName && chunkData.sliceId == sliceId) { + if (chunkIntents[chunkData.chunkIndex] == null) { + chunkIntents[chunkData.chunkIndex] = intent } } } downloadBundle.put(BundleKeys.CHUNK_INTENTS, moduleName, sliceId, chunkIntents) - downloadBundle.put(BundleKeys.UNCOMPRESSED_SIZE, moduleName, sliceId, uncompressedSize) - downloadBundle.put(BundleKeys.COMPRESSION_FORMAT, moduleName, sliceId, 1) // TODO - downloadBundle.put(BundleKeys.UNCOMPRESSED_HASH_SHA256, moduleName, sliceId, uncompressedHashSha256) + downloadBundle.put(BundleKeys.UNCOMPRESSED_SIZE, moduleName, sliceId, it.sliceUncompressedSize) + downloadBundle.put(BundleKeys.COMPRESSION_FORMAT, moduleName, sliceId, it.sliceCompressionFormat) + downloadBundle.put(BundleKeys.UNCOMPRESSED_HASH_SHA256, moduleName, sliceId, it.sliceUncompressedHashSha256) } - downloadBundle.put(BundleKeys.SLICE_IDS, moduleName, ArrayList(packData.chunks.mapNotNull { it.sliceId }.distinct())) + downloadBundle.put(BundleKeys.SLICE_IDS, moduleName, ArrayList(packData.chunks.map { it.sliceId }.distinct())) sendBroadCast(context, downloadData, downloadBundle) return downloadBundle } catch (e: Exception) { diff --git a/vending-app/src/main/proto/AssetModule.proto b/vending-app/src/main/proto/AssetModule.proto index 0f51b0815..deaa3d0c5 100644 --- a/vending-app/src/main/proto/AssetModule.proto +++ b/vending-app/src/main/proto/AssetModule.proto @@ -70,6 +70,6 @@ message PatchInfo { message ChunkInfo { optional int64 bytesToDownload = 1; - optional string unknown = 2; + optional string sha256 = 2; optional string sourceUri = 3; }