Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement SplitInstallService #2500

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ buildscript {

ext.slf4jVersion = '1.7.36'
ext.volleyVersion = '1.2.1'
ext.wireVersion = '4.8.0'
ext.wireVersion = '4.9.9'

ext.androidBuildGradleVersion = '8.2.2'

Expand Down
12 changes: 12 additions & 0 deletions vending-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="com.google.android.gms.permission.READ_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

<uses-permission
android:name="android.permission.USE_CREDENTIALS"
Expand Down Expand Up @@ -148,6 +149,13 @@
</intent-filter>
</activity>

<service android:name="com.google.android.finsky.splitinstallservice.SplitInstallService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.play.core.splitinstall.BIND_SPLIT_INSTALL_SERVICE"/>
</intent-filter>
</service>

<service
android:name="com.android.vending.billing.InAppBillingService"
android:exported="true">
Expand Down Expand Up @@ -175,5 +183,9 @@
</intent-filter>
</service>

<receiver
android:name="com.google.android.finsky.splitinstallservice.SplitInstallManager$InstallResultReceiver"
android:exported="true"/>

</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* SPDX-FileCopyrightText: 2024 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.play.core.splitinstall.protocol;
import com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback;

interface ISplitInstallService {
void startInstall(String pkg,in List<Bundle> splits,in Bundle bundle, ISplitInstallServiceCallback callback) = 1;
void completeInstalls(String pkg, int sessionId,in Bundle bundle, ISplitInstallServiceCallback callback) = 2;
void cancelInstall(String pkg, int sessionId, ISplitInstallServiceCallback callback) = 3;
void getSessionState(String pkg, int sessionId, ISplitInstallServiceCallback callback) = 4;
void getSessionStates(String pkg, ISplitInstallServiceCallback callback) = 5;
void splitRemoval(String pkg,in List<Bundle> splits, ISplitInstallServiceCallback callback) = 6;
void splitDeferred(String pkg,in List<Bundle> splits,in Bundle bundle, ISplitInstallServiceCallback callback) = 7;
void getSessionState2(String pkg, int sessionId, ISplitInstallServiceCallback callback) = 8;
void getSessionStates2(String pkg, ISplitInstallServiceCallback callback) = 9;
void getSplitsAppUpdate(String pkg, ISplitInstallServiceCallback callback) = 10;
void completeInstallAppUpdate(String pkg, ISplitInstallServiceCallback callback) = 11;
void languageSplitInstall(String pkg,in List<Bundle> splits,in Bundle bundle, ISplitInstallServiceCallback callback) = 12;
void languageSplitUninstall(String pkg,in List<Bundle> splits, ISplitInstallServiceCallback callback) =13;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* SPDX-FileCopyrightText: 2024 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.play.core.splitinstall.protocol;


interface ISplitInstallServiceCallback {
oneway void onStartInstall(int status, in Bundle bundle) = 1;
oneway void onInstallCompleted(int status, in Bundle bundle) = 2;
oneway void onCancelInstall(int status, in Bundle bundle) = 3;
oneway void onGetSessionState(int status, in Bundle bundle) = 4;
oneway void onError(in Bundle bundle) = 5;
oneway void onGetSessionStates(in List<Bundle> list) = 6;
oneway void onDeferredUninstall(in Bundle bundle) = 7;
oneway void onDeferredInstall(in Bundle bundle) = 8;
oneway void onDeferredLanguageInstall(in Bundle bundle) = 11;
oneway void onDeferredLanguageUninstall(in Bundle bundle) = 12;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@ package com.android.vending.licensing

import android.accounts.Account
import android.accounts.AccountManager
import android.accounts.AccountManagerFuture
import android.accounts.AuthenticatorException
import android.accounts.OperationCanceledException
import android.content.pm.PackageInfo
import android.os.Bundle
import android.os.RemoteException
import android.util.Log
import com.android.vending.AUTH_TOKEN_SCOPE
import com.android.vending.LicenseResult
import com.android.vending.buildRequestHeaders
import com.android.vending.getAuthToken
import com.android.volley.VolleyError
import org.microg.vending.billing.core.HttpClient
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

private const val TAG = "FakeLicenseChecker"

Expand Down Expand Up @@ -69,8 +67,6 @@ const val ERROR_INVALID_PACKAGE_NAME: Int = 0x102
*/
const val ERROR_NON_MATCHING_UID: Int = 0x103

const val AUTH_TOKEN_SCOPE: String = "oauth2:https://www.googleapis.com/auth/googleplay"

sealed class LicenseRequestParameters
data class V1Parameters(
val nonce: Long
Expand Down Expand Up @@ -108,7 +104,7 @@ suspend fun HttpClient.checkLicense(
) : LicenseResponse {

val auth = try {
accountManager.getAuthToken(account, AUTH_TOKEN_SCOPE, false)
getAuthToken(accountManager, account, AUTH_TOKEN_SCOPE)
.getString(AccountManager.KEY_AUTHTOKEN)
} catch (e: AuthenticatorException) {
Log.e(TAG, "Could not fetch auth token for account $account")
Expand Down Expand Up @@ -145,7 +141,7 @@ suspend fun HttpClient.makeLicenseV1Request(
packageName: String, auth: String, versionCode: Int, nonce: Long, androidId: Long
): V1Response? = get(
url = "https://play-fe.googleapis.com/fdfe/apps/checkLicense?pkgn=$packageName&vc=$versionCode&nnc=$nonce",
headers = getLicenseRequestHeaders(auth, androidId),
headers = buildRequestHeaders(auth, androidId),
adapter = LicenseResult.ADAPTER
).information?.v1?.let {
if (it.result != null && it.signedData != null && it.signature != null) {
Expand All @@ -160,22 +156,9 @@ suspend fun HttpClient.makeLicenseV2Request(
androidId: Long
): V2Response? = get(
url = "https://play-fe.googleapis.com/fdfe/apps/checkLicenseServerFallback?pkgn=$packageName&vc=$versionCode",
headers = getLicenseRequestHeaders(auth, androidId),
headers = buildRequestHeaders(auth, androidId),
adapter = LicenseResult.ADAPTER
).information?.v2?.license?.jwt?.let {
// Field present ←→ user has license
V2Response(LICENSED, it)
}


suspend fun AccountManager.getAuthToken(account: Account, authTokenType: String, notifyAuthFailure: Boolean) =
suspendCoroutine { continuation ->
getAuthToken(account, authTokenType, notifyAuthFailure, { future: AccountManagerFuture<Bundle> ->
try {
val result = future.result
continuation.resume(result)
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}, null)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,47 @@ import com.squareup.wire.Message
import com.squareup.wire.ProtoAdapter
import org.json.JSONObject
import org.microg.gms.utils.singleInstanceOf
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

private const val POST_TIMEOUT = 8000

class HttpClient(context: Context) {
private val requestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }

val requestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }

suspend fun download(url: String, downloadFile: File, tag: String): String = suspendCoroutine { continuation ->
val uriBuilder = Uri.parse(url).buildUpon()
requestQueue.add(object : Request<String>(Method.GET, uriBuilder.build().toString(), null) {
override fun parseNetworkResponse(response: NetworkResponse): Response<String> {
if (response.statusCode != 200) throw VolleyError(response)
return try {
val parentDir = downloadFile.getParentFile()
if (parentDir != null && !parentDir.exists() && !parentDir.mkdirs()) {
throw IOException("Failed to create directories: ${parentDir.absolutePath}")
}
val fos = FileOutputStream(downloadFile)
fos.write(response.data)
fos.close()
Response.success(downloadFile.absolutePath, HttpHeaderParser.parseCacheHeaders(response))
} catch (e: Exception) {
Response.error(VolleyError(e))
}
}

override fun deliverResponse(response: String) {
continuation.resume(response)
}

override fun deliverError(error: VolleyError) {
continuation.resumeWithException(error)
}
}.setShouldCache(false).setTag(tag))
}

suspend fun <O> get(
url: String,
Expand Down
Loading