Skip to content

Commit 207ef83

Browse files
authored
Asset: Fixed game resource download issues (#3124)
1 parent f9d1556 commit 207ef83

1 file changed

Lines changed: 57 additions & 32 deletions

File tree

vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/AssetModuleService.kt

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,32 @@ class AssetModuleServiceImpl(
5656
private val packageDownloadData: MutableMap<String, DownloadData?>
5757
) : AbstractAssetModuleServiceImpl(context, lifecycle) {
5858
private val fileDescriptorMap = mutableMapOf<File, ParcelFileDescriptor>()
59+
private val lock = Any()
5960

6061
private fun checkSessionValid(packageName: String, sessionId: Int) {
62+
Log.d(TAG, "checkSessionValid: $packageName $sessionId ${packageDownloadData[packageName]?.sessionIds}")
6163
if (packageDownloadData[packageName]?.sessionIds?.values?.contains(sessionId) != true) {
6264
Log.w(TAG, "No active session with id $sessionId in $packageName")
6365
throw AssetPackException(AssetPackErrorCode.ACCESS_DENIED)
6466
}
6567
}
6668

67-
override fun getDefaultSessionId(packageName: String, moduleName: String): Int =
69+
override fun getDefaultSessionId(packageName: String, moduleName: String): Int = synchronized(lock) {
6870
packageDownloadData[packageName]?.sessionIds?.get(moduleName) ?: 0
71+
}
6972

7073
override suspend fun startDownload(params: StartDownloadParameters, packageName: String, callback: IAssetModuleServiceCallback?) {
71-
if (packageDownloadData[packageName] == null ||
72-
packageDownloadData[packageName]?.packageName != packageName ||
73-
packageDownloadData[packageName]?.moduleNames?.intersect(params.moduleNames.toSet())?.isEmpty() == true) {
74-
packageDownloadData[packageName] = httpClient.initAssetModuleData(context, packageName, accountManager, params.moduleNames, params.options)
74+
val needInit = synchronized(lock) {
75+
packageDownloadData[packageName] == null ||
76+
packageDownloadData[packageName]?.packageName != packageName ||
77+
packageDownloadData[packageName]?.moduleNames?.intersect(params.moduleNames.toSet())?.isEmpty() == true
78+
}
79+
80+
if (needInit) {
81+
val newData = httpClient.initAssetModuleData(context, packageName, accountManager, params.moduleNames, params.options)
82+
synchronized(lock) {
83+
packageDownloadData[packageName] = packageDownloadData[packageName].merge(newData)
84+
}
7585
if (packageDownloadData[packageName] == null) {
7686
throw AssetPackException(AssetPackErrorCode.API_NOT_AVAILABLE)
7787
}
@@ -114,24 +124,26 @@ class AssetModuleServiceImpl(
114124
override suspend fun getSessionStates(params: GetSessionStatesParameters, packageName: String, callback: IAssetModuleServiceCallback?) {
115125
val listBundleData: MutableList<Bundle> = mutableListOf()
116126

117-
if (packageDownloadData[packageName] != null && packageDownloadData[packageName]?.moduleNames?.all {
118-
packageDownloadData[packageName]?.getModuleData(it)?.status == AssetPackStatus.COMPLETED
119-
} == true && params.installedAssetModules.isEmpty()) {
120-
Log.d(TAG, "getSessionStates: resetAllModuleStatus: $listBundleData")
121-
packageDownloadData[packageName]?.resetAllModuleStatus()
122-
callback?.onGetSessionStates(listBundleData)
123-
return
124-
}
127+
synchronized(lock) {
128+
if (packageDownloadData[packageName] != null && packageDownloadData[packageName]?.moduleNames?.all {
129+
packageDownloadData[packageName]?.getModuleData(it)?.status == AssetPackStatus.COMPLETED
130+
} == true && params.installedAssetModules.isEmpty()) {
131+
Log.d(TAG, "getSessionStates: resetAllModuleStatus: $listBundleData")
132+
packageDownloadData[packageName]?.resetAllModuleStatus()
133+
callback?.onGetSessionStates(listBundleData)
134+
return
135+
}
125136

126-
packageDownloadData[packageName]?.moduleNames?.forEach { moduleName ->
127-
if (moduleName in params.installedAssetModules) return@forEach
137+
packageDownloadData[packageName]?.moduleNames?.forEach { moduleName ->
138+
if (moduleName in params.installedAssetModules) return@forEach
128139

129-
listBundleData.add(sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, null, null))
140+
listBundleData.add(sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, null, null))
130141

131-
packageDownloadData[packageName]?.getModuleData(moduleName)?.chunks?.forEach { chunkData ->
132-
val destination = chunkData.getChunkFile(context)
133-
if (destination.exists() && destination.length() == chunkData.chunkBytesToDownload) {
134-
sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, chunkData, destination)
142+
packageDownloadData[packageName]?.getModuleData(moduleName)?.chunks?.forEach { chunkData ->
143+
val destination = chunkData.getChunkFile(context)
144+
if (destination.exists() && destination.length() == chunkData.chunkBytesToDownload) {
145+
sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, chunkData, destination)
146+
}
135147
}
136148
}
137149
}
@@ -143,9 +155,11 @@ class AssetModuleServiceImpl(
143155
override suspend fun notifyChunkTransferred(params: NotifyChunkTransferredParameters, packageName: String, callback: IAssetModuleServiceCallback?) {
144156
checkSessionValid(packageName, params.sessionId)
145157

146-
val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber)
147-
fileDescriptorMap[downLoadFile]?.close()
148-
fileDescriptorMap.remove(downLoadFile)
158+
synchronized(lock) {
159+
val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber)
160+
fileDescriptorMap[downLoadFile]?.close()
161+
fileDescriptorMap.remove(downLoadFile)
162+
}
149163
// TODO: Remove chunk after successful transfer of chunk or only with module?
150164
callback?.onNotifyChunkTransferred(
151165
bundleOf(BundleKeys.MODULE_NAME to params.moduleName) +
@@ -159,8 +173,10 @@ class AssetModuleServiceImpl(
159173
override suspend fun notifyModuleCompleted(params: NotifyModuleCompletedParameters, packageName: String, callback: IAssetModuleServiceCallback?) {
160174
checkSessionValid(packageName, params.sessionId)
161175

162-
packageDownloadData[packageName]?.updateDownloadStatus(params.moduleName, AssetPackStatus.COMPLETED)
163-
sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, params.moduleName, null, null)
176+
synchronized(lock) {
177+
packageDownloadData[packageName]?.updateDownloadStatus(params.moduleName, AssetPackStatus.COMPLETED)
178+
sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, params.moduleName, null, null)
179+
}
164180

165181
val directory = context.getModuleDir(params.sessionId, params.moduleName)
166182
if (directory.exists()) {
@@ -192,9 +208,11 @@ class AssetModuleServiceImpl(
192208
override suspend fun getChunkFileDescriptor(params: GetChunkFileDescriptorParameters, packageName: String, callback: IAssetModuleServiceCallback?) {
193209
checkSessionValid(packageName, params.sessionId)
194210

195-
val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber)
196-
val parcelFileDescriptor = ParcelFileDescriptor.open(downLoadFile, ParcelFileDescriptor.MODE_READ_ONLY).also {
197-
fileDescriptorMap[downLoadFile] = it
211+
val parcelFileDescriptor = synchronized(lock) {
212+
val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber)
213+
ParcelFileDescriptor.open(downLoadFile, ParcelFileDescriptor.MODE_READ_ONLY).also {
214+
fileDescriptorMap[downLoadFile] = it
215+
}
198216
}
199217

200218
Log.d(TAG, "getChunkFileDescriptor -> $parcelFileDescriptor")
@@ -205,10 +223,17 @@ class AssetModuleServiceImpl(
205223
}
206224

207225
override suspend fun requestDownloadInfo(params: RequestDownloadInfoParameters, packageName: String, callback: IAssetModuleServiceCallback?) {
208-
if (packageDownloadData[packageName] == null ||
209-
packageDownloadData[packageName]?.packageName != packageName ||
210-
packageDownloadData[packageName]?.moduleNames?.intersect(params.moduleNames.toSet())?.isEmpty() == true) {
211-
packageDownloadData[packageName] = httpClient.initAssetModuleData(context, packageName, accountManager, params.moduleNames, params.options)
226+
val needInit = synchronized(lock) {
227+
packageDownloadData[packageName] == null ||
228+
packageDownloadData[packageName]?.packageName != packageName ||
229+
packageDownloadData[packageName]?.moduleNames?.intersect(params.moduleNames.toSet())?.isEmpty() == true
230+
}
231+
232+
if (needInit) {
233+
val newData = httpClient.initAssetModuleData(context, packageName, accountManager, params.moduleNames, params.options)
234+
synchronized(lock) {
235+
packageDownloadData[packageName] = packageDownloadData[packageName].merge(newData)
236+
}
212237
if (packageDownloadData[packageName] == null) {
213238
throw AssetPackException(AssetPackErrorCode.API_NOT_AVAILABLE)
214239
}

0 commit comments

Comments
 (0)