1+ /*
2+ * SPDX-FileCopyrightText: 2025 microG Project Team
3+ * SPDX-License-Identifier: Apache-2.0
4+ */
5+
6+ package org.microg.gms.auth.blockstore
7+
8+ import android.os.Bundle
9+ import android.util.Log
10+ import androidx.lifecycle.Lifecycle
11+ import androidx.lifecycle.LifecycleOwner
12+ import androidx.lifecycle.lifecycleScope
13+ import com.google.android.gms.auth.blockstore.AppRestoreInfo
14+ import com.google.android.gms.auth.blockstore.BlockstoreStatusCodes
15+ import com.google.android.gms.auth.blockstore.DeleteBytesRequest
16+ import com.google.android.gms.auth.blockstore.RetrieveBytesRequest
17+ import com.google.android.gms.auth.blockstore.RetrieveBytesResponse
18+ import com.google.android.gms.auth.blockstore.StoreBytesData
19+ import com.google.android.gms.auth.blockstore.internal.IBlockstoreService
20+ import com.google.android.gms.auth.blockstore.internal.IDeleteBytesCallback
21+ import com.google.android.gms.auth.blockstore.internal.IGetAccessForPackageCallback
22+ import com.google.android.gms.auth.blockstore.internal.IGetBlockstoreDataCallback
23+ import com.google.android.gms.auth.blockstore.internal.IIsEndToEndEncryptionAvailableCallback
24+ import com.google.android.gms.auth.blockstore.internal.IRetrieveBytesCallback
25+ import com.google.android.gms.auth.blockstore.internal.ISetBlockstoreDataCallback
26+ import com.google.android.gms.auth.blockstore.internal.IStoreBytesCallback
27+ import com.google.android.gms.common.Feature
28+ import com.google.android.gms.common.api.CommonStatusCodes
29+ import com.google.android.gms.common.api.Status
30+ import com.google.android.gms.common.api.internal.IStatusCallback
31+ import com.google.android.gms.common.internal.ConnectionInfo
32+ import com.google.android.gms.common.internal.GetServiceRequest
33+ import com.google.android.gms.common.internal.IGmsCallbacks
34+ import kotlinx.coroutines.launch
35+ import org.microg.gms.BaseService
36+ import org.microg.gms.common.GmsService
37+ import org.microg.gms.common.GmsService.BLOCK_STORE
38+ import org.microg.gms.common.PackageUtils
39+
40+ private const val TAG = " BlockstoreApiService"
41+
42+ private val FEATURES = arrayOf(
43+ Feature (" auth_blockstore" , 3 ),
44+ Feature (" blockstore_data_transfer" , 1 ),
45+ Feature (" blockstore_notify_app_restore" , 1 ),
46+ Feature (" blockstore_store_bytes_with_options" , 2 ),
47+ Feature (" blockstore_is_end_to_end_encryption_available" , 1 ),
48+ Feature (" blockstore_enable_cloud_backup" , 1 ),
49+ Feature (" blockstore_delete_bytes" , 2 ),
50+ Feature (" blockstore_retrieve_bytes_with_options" , 3 ),
51+ Feature (" auth_clear_restore_credential" , 2 ),
52+ Feature (" auth_create_restore_credential" , 1 ),
53+ Feature (" auth_get_restore_credential" , 1 ),
54+ Feature (" auth_get_private_restore_credential_key" , 1 ),
55+ Feature (" auth_set_private_restore_credential_key" , 1 ),
56+ )
57+
58+ class BlockstoreApiService : BaseService (TAG , BLOCK_STORE ) {
59+
60+ override fun handleServiceRequest (callback : IGmsCallbacks , request : GetServiceRequest , service : GmsService ) {
61+ try {
62+ val packageName = PackageUtils .getAndCheckCallingPackage(this , request.packageName) ? : throw IllegalArgumentException (" Missing package name" )
63+
64+ val blockStoreImpl = BlockStoreImpl (this , packageName)
65+ callback.onPostInitCompleteWithConnectionInfo(
66+ CommonStatusCodes .SUCCESS , BlobstoreServiceImpl (blockStoreImpl, lifecycle).asBinder(), ConnectionInfo ().apply { features = FEATURES })
67+ } catch (e: Exception ) {
68+ Log .w(TAG , " handleServiceRequest" , e)
69+ callback.onPostInitComplete(CommonStatusCodes .INTERNAL_ERROR , null , null )
70+ }
71+ }
72+ }
73+
74+ class BlobstoreServiceImpl (val blockStore : BlockStoreImpl , override val lifecycle : Lifecycle ) : IBlockstoreService.Stub(), LifecycleOwner {
75+
76+ override fun retrieveBytes (callback : IRetrieveBytesCallback ? ) {
77+ Log .d(TAG , " Method (retrieveBytes) called" )
78+ lifecycleScope.launch {
79+ runCatching {
80+ val retrieveBytes = blockStore.retrieveBytes()
81+ if (retrieveBytes != null ) {
82+ callback?.onBytesResult(Status .SUCCESS , retrieveBytes)
83+ } else {
84+ callback?.onBytesResult(Status .INTERNAL_ERROR , null )
85+ }
86+ }
87+ }
88+ }
89+
90+ override fun setBlockstoreData (callback : ISetBlockstoreDataCallback ? , data : ByteArray? ) {
91+ Log .d(TAG , " Method (setBlockstoreData: ${data?.size} ) called but not implemented" )
92+ }
93+
94+ override fun getBlockstoreData (callback : IGetBlockstoreDataCallback ? ) {
95+ Log .d(TAG , " Method (getBlockstoreData) called but not implemented" )
96+ }
97+
98+ override fun getAccessForPackage (callback : IGetAccessForPackageCallback ? , packageName : String? ) {
99+ Log .d(TAG , " Method (getAccessForPackage: $packageName ) called but not implemented" )
100+ }
101+
102+ override fun setFlagWithPackage (callback : IStatusCallback ? , packageName : String? , flag : Int ) {
103+ Log .d(TAG , " Method (setFlagWithPackage: $packageName , $flag ) called but not implemented" )
104+ }
105+
106+ override fun clearFlagForPackage (callback : IStatusCallback ? , packageName : String? ) {
107+ Log .d(TAG , " Method (clearFlagForPackage: $packageName ) called but not implemented" )
108+ }
109+
110+ override fun updateFlagForPackage (callback : IStatusCallback ? , packageName : String? , value : Int ) {
111+ Log .d(TAG , " Method (updateFlagForPackage: $packageName , $value ) called but not implemented" )
112+ }
113+
114+ override fun reportAppRestore (callback : IStatusCallback ? , packages : List <String ?>? , code : Int , info : AppRestoreInfo ? ) {
115+ Log .d(TAG , " Method (reportAppRestore: $packages , $code , $info ) called but not implemented" )
116+ }
117+
118+ override fun storeBytes (callback : IStoreBytesCallback ? , data : StoreBytesData ? ) {
119+ Log .d(TAG , " Method (storeBytes: $data ) called" )
120+ lifecycleScope.launch {
121+ runCatching {
122+ val storeBytes = blockStore.storeBytes(data)
123+ Log .d(TAG , " storeBytes: size: $storeBytes " )
124+ when (storeBytes) {
125+ 0 -> callback?.onStoreBytesResult(Status .INTERNAL_ERROR , BlockstoreStatusCodes .FEATURE_NOT_SUPPORTED )
126+ BlockstoreStatusCodes .MAX_SIZE_EXCEEDED -> callback?.onStoreBytesResult(Status .INTERNAL_ERROR , BlockstoreStatusCodes .MAX_SIZE_EXCEEDED )
127+ BlockstoreStatusCodes .TOO_MANY_ENTRIES -> callback?.onStoreBytesResult(Status .INTERNAL_ERROR , BlockstoreStatusCodes .TOO_MANY_ENTRIES )
128+ else -> callback?.onStoreBytesResult(Status .SUCCESS , storeBytes)
129+ }
130+ }
131+ }
132+ }
133+
134+ override fun isEndToEndEncryptionAvailable (callback : IIsEndToEndEncryptionAvailableCallback ? ) {
135+ Log .d(TAG , " Method (isEndToEndEncryptionAvailable) called" )
136+ runCatching { callback?.onCheckEndToEndEncryptionResult(Status .SUCCESS , false ) }
137+ }
138+
139+ override fun retrieveBytesWithRequest (callback : IRetrieveBytesCallback ? , request : RetrieveBytesRequest ? ) {
140+ Log .d(TAG , " Method (retrieveBytesWithRequest: $request ) called" )
141+ lifecycleScope.launch {
142+ runCatching {
143+ val retrieveBytesResponse = blockStore.retrieveBytesWithRequest(request)
144+ Log .d(TAG , " retrieveBytesWithRequest: retrieveBytesResponse: $retrieveBytesResponse " )
145+ if (retrieveBytesResponse != null ) {
146+ callback?.onResponseResult(Status .SUCCESS , retrieveBytesResponse)
147+ } else {
148+ callback?.onResponseResult(Status .INTERNAL_ERROR , RetrieveBytesResponse (Bundle .EMPTY , emptyList()))
149+ }
150+ }
151+ }
152+ }
153+
154+ override fun deleteBytes (callback : IDeleteBytesCallback ? , request : DeleteBytesRequest ? ) {
155+ Log .d(TAG , " Method (deleteBytes: $request ) called" )
156+ lifecycleScope.launch {
157+ runCatching {
158+ val deleted = blockStore.deleteBytesWithRequest(request)
159+ callback?.onDeleteBytesResult(Status .SUCCESS , deleted)
160+ }
161+ }
162+ }
163+ }
0 commit comments