Skip to content

Commit

Permalink
Implement SplitInstallService
Browse files Browse the repository at this point in the history
When a 3rd party app wants to install a split APK, the application
tries to bind to a SplitInstallService through the
SplitInstallManager part of the Google Play Feature Delivery
Library.

The implementation of SplitInstallService allows us to catch
the install requests coming from the 3rd party app and handle
them.

As an example, DummyStoreSplitInstaller binds to an external
com.dummy.store.splitinstall.SplitInstallService service which
is able to retrieve the split APKs from the com.dummy.store.
  • Loading branch information
jonathanklee authored and ale5000-git committed Feb 6, 2024
1 parent 048a6e5 commit e41e442
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 0 deletions.
12 changes: 12 additions & 0 deletions vending-app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
namespace "com.android.vending"
Expand Down Expand Up @@ -46,10 +47,21 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = 1.8
}
}

repositories {
mavenCentral()
}

dependencies {
implementation project(':fake-signature')

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"
}

if (file('user.gradle').exists()) {
Expand Down
7 changes: 7 additions & 0 deletions vending-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@
</intent-filter>
</service>

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

<activity
android:name="org.microg.vending.ui.MainActivity"
android:theme="@style/Theme.Dialog.NoActionBar"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2013-2022 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.dummy.store;

interface IDummyStoreSplitInstallService {
void installSplitModule(String packageName, String moduleName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2013-2022 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.play.core.splitinstall.protocol;

import com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback;

interface ISplitInstallService {

// Method not identified yet
void a();

void startInstall(String str, in List<Bundle> list, in Bundle bundle, in ISplitInstallServiceCallback callback);

// Method not identified yet
void c(String str);

// Method not identified yet
void d(String str);

// Method not identified yet
void e(String str);

void getSessionStates(String str, in ISplitInstallServiceCallback callback);

// Method not identified yet
void g(String str);

// Method not identified yet
void h(String str, in ISplitInstallServiceCallback callback);

// Method not identified yet
void i(String str);

// Method not identified yet
void j(String str);

// Method not identified yet
void k(String str);

// Method not identified yet
void l(String str);

// Method not identified yet
void m(String str);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2013-2022 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.play.core.splitinstall.protocol;

import android.os.Bundle;

interface ISplitInstallServiceCallback {

void onStartInstall(int i, in Bundle bundle);

// Method not identified yet
void b();

void onCompleteInstall(int i);

void onCancelInstall(int i, in Bundle bundle);

void onGetSession(int i, in Bundle bundle);

void onError(in Bundle bundle);

void onGetSessionStates(in List<Bundle> list);

void onDeferredUninstall(in Bundle bundle);

void onDeferredInstall(in Bundle bundle);

void onGetSplitsForAppUpdate();

void onCompleteInstallForAppUpdate();

void onDeferredLanguageInstall();
}
120 changes: 120 additions & 0 deletions vending-app/src/main/java/com/android/vending/SplitInstallService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2013-2022 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.vending

import android.app.Service
import android.content.Intent
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import com.android.vending.splitinstall.SplitInstaller
import com.android.vending.splitinstall.SplitInstallerFactory
import com.android.vending.splitinstall.SplitInstallerType
import com.google.android.play.core.splitinstall.protocol.ISplitInstallService
import com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback

class SplitInstallService : Service() {

companion object {
const val TAG = "SplitInstallService"
}

private lateinit var mSplitInstaller: SplitInstaller

override fun onCreate() {
super.onCreate()

mSplitInstaller = SplitInstallerFactory.createSplitInstaller(
applicationContext,
SplitInstallerType.DummyStoreSplitInstaller
)

mSplitInstaller.initialize()
}

override fun onBind(p0: Intent?): IBinder {
return mServiceInterface
}

override fun onDestroy() {
super.onDestroy()
mSplitInstaller.destroy()
}

private var mServiceInterface = object : ISplitInstallService.Stub() {

override fun a() {
Log.d(TAG, "a")
}

override fun startInstall(
packageName: String,
list: List<Bundle>,
bundle: Bundle,
callback: ISplitInstallServiceCallback
) {
for (element in list) {
mSplitInstaller.install(packageName, element.get("module_name").toString())
}
}

override fun c(str: String?) {
Log.d(TAG, "c")
}

override fun d(str: String?) {
Log.d(TAG, "d")
}

override fun e(str: String?) {
Log.d(TAG, "e")
}

override fun getSessionStates(str: String, callback: ISplitInstallServiceCallback) {
Log.d(TAG, "onGetSessionStates")
callback.onGetSessionStates(arrayListOf<Bundle>())
}

override fun g(str: String?) {
Log.d(TAG, "g")
}

override fun h(str: String?, callback: ISplitInstallServiceCallback?) {
Log.d(TAG, "h $str $callback")
}

override fun i(str: String?) {
Log.d(TAG, "i")
}

override fun j(str: String?) {
Log.d(TAG, "j")
}

override fun k(str: String?) {
Log.d(TAG, "k")
}

override fun l(str: String?) {
Log.d(TAG, "l")
}

override fun m(str: String?) {
Log.d(TAG, "m")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2013-2022 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.vending.splitinstall

interface SplitInstallErrorCode {
companion object {
const val API_NOT_AVAILABLE = -5
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2013-2022 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.vending.splitinstall

import android.content.Context
import com.android.vending.splitinstall.installer.DummyStoreSplitInstaller

interface SplitInstaller {
fun initialize()
fun install(packageName: String, moduleName: String)
fun destroy()
}

enum class SplitInstallerType { DummyStoreSplitInstaller }

object SplitInstallerFactory {
fun createSplitInstaller(context: Context, type: SplitInstallerType): SplitInstaller {
when (type) {
SplitInstallerType.DummyStoreSplitInstaller ->
return DummyStoreSplitInstaller(context)
else -> throw IllegalArgumentException("Unknown SplitInstallerType")
}
}
}
Loading

0 comments on commit e41e442

Please sign in to comment.