core中的代码
首先我们在代码中调用了
manager = SplitInstallManagerFactory.create(this)
1.SplitInstallManagerFactory.class
public class SplitInstallManagerFactory {
public static SplitInstallManager create(Context context) {
return new h(new k(context), context);
}
}
2.com.google.android.play.core.splitinstall.k.class
final class k {
private static final b b = new b("SplitInstallService");
private static final Intent c = new Intent("com.google.android.play.core.splitinstall.BIND_SPLIT_INSTALL_SERVICE").setPackage("com.android.vending");
final com.google.android.play.core.a.b<a> a;
private final Context d;
private final String e;
private final f f;
public k(Context context) {
this(context, context.getPackageName());//这个是需要传给Google play的包名
}
private k(Context context, String str) {
this.f = new j(this);
this.d = context;
this.e = str;
this.a = new com.google.android.play.core.a.b(context.getApplicationContext(), b, "SplitInstallService", c, l.a, this.f);
}
可以看到直接调用到了c这个service,我们在自己代码里没有找到这个相关Service,
我们反编译Google play和Google Play Service发现这段代码在google play的应用商店中。
3.Google Play的代码:
<service finsky:name="com.google.android.finsky.splitinstallservice.SplitInstallService" finsky:enabled="true" finsky:exported="true" finsky:visibleToInstantApps="true">
<meta-data finsky:name="instantapps.clients.allowed" finsky:value="true" />
<intent-filter>
<action finsky:name="com.google.android.play.core.splitinstall.BIND_SPLIT_INSTALL_SERVICE" />
</intent-filter>
</service>
4.现在流程基本上打通了,下面看看我们安装的时候,代码流程。
private fun loadAndLaunchModule(name: String) {
updateProgressMessage("Loading module $name")
// Skip loading if the module already is installed. Perform success action directly.
if (manager.installedModules.contains(name)) {
updateProgressMessage("Already installed")
onSuccessfulLoad(name, launch = true)
return
}
// Create request to install a feature module by name.
val request = SplitInstallRequest.newBuilder()
.addModule(name)
.build()
// Load and install the requested feature module.
manager.startInstall(request)
updateProgressMessage("Starting install for $name")
}
5.manager.startInstall
进入com.google.android.play.core.splitinstall.h中:
public final Task<Integer> startInstall(SplitInstallRequest splitInstallRequest) {
if (!getInstalledModules().containsAll(splitInstallRequest.getModuleNames())) {
return this.b.a(splitInstallRequest.getModuleNames());//这个就是前面的k.class
}
this.f.post(new i(this, splitInstallRequest));
return Tasks.a(Integer.valueOf(0));
}
6.回到com.google.android.play.core.splitinstall.k.class
public final Task<Integer> a(Collection<String> collection) {
b.a("startInstall(%s)", collection);
i iVar = new i();
this.a.a(new m(this, iVar, collection, iVar));
return iVar.a();
}
//我的理解这个应该走下面,但实际走的是上面(安装/卸载)
public final Task<Void> a(List<String> list) {
b.a("deferredUninstall(%s)", list);
i iVar = new i();
this.a.a(new n(this, iVar, list, iVar));
return iVar.a();
}
7.进入:com.google.android.play.core.a.b中
public final void a(a aVar) {
c(new d(this, aVar));//d是个Runnable类型
}
private final void c(a aVar) {
d().post(aVar);
}
private final Handler d() {
Handler handler;
synchronized (a) {
if (!a.containsKey(this.d)) {
HandlerThread handlerThread = new HandlerThread(this.d, 10);
handlerThread.start();
a.put(this.d, new Handler(handlerThread.getLooper()));
}
handler = (Handler) a.get(this.d);
}
return handler;
}
8.所以这个就是直接运行d类
package com.google.android.play.core.a;
final class d extends a {
private final /* synthetic */ a a;
private final /* synthetic */ b b;
d(b bVar, a aVar) {
this.b = bVar;
this.a = aVar;
}
public final void b() {
this.b.b(this.a);
}
}
9.先看看父类a
package com.google.android.play.core.a;
import com.google.android.play.core.tasks.i;
public abstract class a implements Runnable {
private final i<?> a;
a() {
this.a = null;
}
public a(i<?> iVar) {
this.a = iVar;
}
final i<?> a() {
return this.a;
}
protected abstract void b();
public final void run() {
try {
b();//这里调用的就是子类的b方法
} catch (Exception e) {
if (this.a != null) {
this.a.a(e);
}
}
}
}
10.所以b方法的代码调用到了
com.google.android.play.core.a.b.class
private final void b(a aVar) {
if (this.l == null && !this.f) {
this.c.a("Initiate binding to the service.", new Object[0]);
this.e.add(aVar);
this.k = new h();
this.f = true;
if (!this.b.bindService(this.g, this.k, 1)) {
this.c.a("Failed to bind to the service.", new Object[0]);
this.f = false;
for (a a : this.e) {
i a2 = a.a();
if (a2 != null) {
a2.a(new k());
}
}
this.e.clear();
}
} else if (this.f) {
this.c.a("Waiting to bind to the service.", new Object[0]);
this.e.add(aVar);
} else {
aVar.run();
}
}
在第六步中,卸载的话构建的 new n()进入
final class n extends a {
private final /* synthetic */ List a;
private final /* synthetic */ i b;
private final /* synthetic */ k c;
n(k kVar, i iVar, List list, i iVar2) {
this.c = kVar;
this.a = list;
this.b = iVar2;
super(iVar);
}
protected final void b() {
try {
((com.google.android.play.core.splitinstall.a.a) this.c.a.b()).b(this.c.e, k.c(this.a), k.e(), new u(this.c, this.b));
} catch (Throwable e) {
k.b.a(e, "deferredUninstall(%s)", this.a);
this.b.a(new RuntimeException(e));
}
}
}
看看b方法的参数,
this.c.e//第六步提到过的应用报名
k.c(this.a)//第六步提到的bundle 列表,
k.e() //bundle 代码中写死的
new u(this.c, this.b)//这是个binder,真正可以通信的类
在第六步中,安装的话构建的 new m()进入
~~~~~~~~~~~~~~~~~~~~~~~~~~~~中间省略N部逻辑
直接到binder通信的地方:
package com.google.android.play.core.splitinstall.a;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.android.a.a;
import java.util.List;
public final class c extends a implements a {
c(IBinder iBinder) {
super(iBinder, "com.google.android.play.core.splitinstall.protocol.ISplitInstallService");
}
public final void a(String str, int i, Bundle bundle, d dVar) {
Parcel a = a();
a.writeString(str);
a.writeInt(i);
com.google.android.a.c.a(a, (Parcelable) bundle);
com.google.android.a.c.a(a, (IInterface) dVar);
a(4, a);
}
public final void a(String str, int i, d dVar) {
Parcel a = a();
a.writeString(str);
a.writeInt(i);
com.google.android.a.c.a(a, (IInterface) dVar);
a(5, a);
}
public final void a(String str, d dVar) {
Parcel a = a();
a.writeString(str);
com.google.android.a.c.a(a, (IInterface) dVar);
a(6, a);
}
public final void a(String str, List<Bundle> list, Bundle bundle, d dVar) {
Parcel a = a();
a.writeString(str);
a.writeTypedList(list);
com.google.android.a.c.a(a, (Parcelable) bundle);
com.google.android.a.c.a(a, (IInterface) dVar);
a(2, a);
}
public final void b(String str, List<Bundle> list, Bundle bundle, d dVar) {
Parcel a = a();
a.writeString(str);
a.writeTypedList(list);
com.google.android.a.c.a(a, (Parcelable) bundle);
com.google.android.a.c.a(a, (IInterface) dVar);
a(7, a);
}
public final void c(String str, List<Bundle> list, Bundle bundle, d dVar) {
Parcel a = a();
a.writeString(str);
a.writeTypedList(list);
com.google.android.a.c.a(a, (Parcelable) bundle);
com.google.android.a.c.a(a, (IInterface) dVar);
a(8, a);
}
}
下面到Google play代码里:
package com.google.android.play.core.d.a;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import com.google.android.a.c;
import java.util.List;
public abstract class b extends com.google.android.a.b implements a {
public b() {
super("com.google.android.play.core.splitinstall.protocol.ISplitInstallService");
}
protected boolean dispatchTransaction(int i, Parcel parcel, Parcel parcel2, int i2) {
c cVar = null;
String readString;
List createTypedArrayList;
Bundle bundle;
IBinder readStrongBinder;
IInterface queryLocalInterface;
int readInt;
IInterface queryLocalInterface2;
c eVar;
IBinder readStrongBinder2;
switch (i) {
case 2:
readString = parcel.readString();
createTypedArrayList = parcel.createTypedArrayList(Bundle.CREATOR);
bundle = (Bundle) c.a(parcel, Bundle.CREATOR);
readStrongBinder = parcel.readStrongBinder();
if (readStrongBinder != null) {
queryLocalInterface = readStrongBinder.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
if (queryLocalInterface instanceof c) {
cVar = (c) queryLocalInterface;
} else {
cVar = new e(readStrongBinder);
}
}
a(readString, createTypedArrayList, bundle, cVar);
break;
case 3:
readString = parcel.readString();
readInt = parcel.readInt();
bundle = (Bundle) c.a(parcel, Bundle.CREATOR);
readStrongBinder = parcel.readStrongBinder();
if (readStrongBinder != null) {
queryLocalInterface = readStrongBinder.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
cVar = queryLocalInterface instanceof c ? (c) queryLocalInterface : new e(readStrongBinder);
}
a(readString, readInt, bundle, cVar);
break;
case 4:
readString = parcel.readString();
readInt = parcel.readInt();
c.a(parcel, Bundle.CREATOR);
readStrongBinder = parcel.readStrongBinder();
if (readStrongBinder != null) {
queryLocalInterface2 = readStrongBinder.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder);
} else {
eVar = null;
}
a(readString, readInt, eVar);
break;
case 5:
readString = parcel.readString();
readInt = parcel.readInt();
readStrongBinder = parcel.readStrongBinder();
if (readStrongBinder != null) {
queryLocalInterface2 = readStrongBinder.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder);
} else {
eVar = null;
}
c(readString, readInt, eVar);
break;
case 6:
readString = parcel.readString();
readStrongBinder2 = parcel.readStrongBinder();
if (readStrongBinder2 != null) {
queryLocalInterface2 = readStrongBinder2.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder2);
} else {
eVar = null;
}
c(readString, eVar);
break;
case 7:
readString = parcel.readString();
createTypedArrayList = parcel.createTypedArrayList(Bundle.CREATOR);
c.a(parcel, Bundle.CREATOR);
readStrongBinder = parcel.readStrongBinder();
if (readStrongBinder != null) {
queryLocalInterface2 = readStrongBinder.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder);
} else {
eVar = null;
}
b(readString, createTypedArrayList, eVar);
break;
case 8:
readString = parcel.readString();
createTypedArrayList = parcel.createTypedArrayList(Bundle.CREATOR);
c.a(parcel, Bundle.CREATOR);
readStrongBinder = parcel.readStrongBinder();
if (readStrongBinder != null) {
queryLocalInterface2 = readStrongBinder.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder);
} else {
eVar = null;
}
a(readString, createTypedArrayList, eVar);
break;
case 9:
readString = parcel.readString();
readInt = parcel.readInt();
c.a(parcel, Bundle.CREATOR);
readStrongBinder = parcel.readStrongBinder();
if (readStrongBinder != null) {
queryLocalInterface2 = readStrongBinder.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder);
} else {
eVar = null;
}
b(readString, readInt, eVar);
break;
case 10:
readString = parcel.readString();
c.a(parcel, Bundle.CREATOR);
readStrongBinder2 = parcel.readStrongBinder();
if (readStrongBinder2 != null) {
queryLocalInterface2 = readStrongBinder2.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder2);
} else {
eVar = null;
}
b(readString, eVar);
break;
case 11:
readString = parcel.readString();
c.a(parcel, Bundle.CREATOR);
readStrongBinder2 = parcel.readStrongBinder();
if (readStrongBinder2 != null) {
queryLocalInterface2 = readStrongBinder2.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder2);
} else {
eVar = null;
}
d(readString, eVar);
break;
case 12:
readString = parcel.readString();
c.a(parcel, Bundle.CREATOR);
readStrongBinder2 = parcel.readStrongBinder();
if (readStrongBinder2 != null) {
queryLocalInterface2 = readStrongBinder2.queryLocalInterface("com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback");
eVar = queryLocalInterface2 instanceof c ? (c) queryLocalInterface2 : new e(readStrongBinder2);
} else {
eVar = null;
}
a(readString, eVar);
break;
default:
return false;
}
return true;
}
}
中间的代码实在是太不好查找了,
但感觉最终安装位置应该是在:
com.google.android.finsky.realtimeinstaller.q
final synchronized void a(String str, ac acVar, int i) {
if (this.f != null) {
throw new IllegalStateException("This session has already been prepared");
}
this.d.set(false);
PackageInstaller packageInstaller = this.a.getPackageManager().getPackageInstaller();
int sessionParams = new SessionParams(i);
sessionParams.setInstallAsInstantApp(this.e);
sessionParams.setDontKillApp(true);
sessionParams.setAppPackageName(str);
try {
c.a("createSession");
sessionParams = packageInstaller.createSession(sessionParams);
packageInstaller.registerSessionCallback(new r(this, sessionParams, str, acVar), new Handler(Looper.getMainLooper()));
c.a("openSession");
packageInstaller = packageInstaller.openSession(sessionParams);
this.f = packageInstaller;
} catch (Throwable th) {
packageInstaller = th;
} finally {
c.a();
}
}
final synchronized void b() {
if (this.f == null) {
throw new IllegalStateException("prepare() was not called on this session");
}
this.b.b(1656);
PendingIntent broadcast = PendingIntent.getBroadcast(this.a, 0, new Intent("com.google.finsky.instantapps.INSTALL_COMMIT"), 134217728);
this.a.registerReceiver(new s(broadcast), new IntentFilter("com.google.finsky.instantapps.INSTALL_COMMIT"));
this.f.commit(broadcast.getIntentSender());
this.f.close();
this.b.b(1646);
this.f = null;
}
为什么这么推测呢?因为这代码实在是太像了,
Google Play的实现原理肯定也是采用split apk的安装方式。
我通过adb测试结果是这样的路径可以达到安装split apk的目的:
wudi:splits xiepengchong$ adb push after_sign.apk /data/local/tmp/0_after_sign.apk
10063 KB/s (1683008 bytes in 0.163s)
wudi:splits xiepengchong$ adb shell pm install-create -r -p com.google.android.samples.dynamicfeatures.ondemand
Success: created install session [899975016]
wudi:splits xiepengchong$ adb shell pm install-write 899975016 0_after_sign.apk /data/local/tmp/0_after_sign.apk
Success: streamed 1683008 bytes
wudi:splits xiepengchong$ adb shell pm install-commit 899975016
而上面的google play代码中,能实现创建session,写session与commit的只有这块代码,还有一块应该是卸载的地方。