Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.StreetViewPanoramaOptions;
import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;
import com.mapbox.mapboxsdk.LibraryLoader;

import org.microg.gms.maps.mapbox.CameraUpdateFactoryImpl;
import org.microg.gms.maps.mapbox.MapFragmentImpl;
import org.microg.gms.maps.mapbox.MapViewImpl;
import org.microg.gms.maps.mapbox.StreetViewPanoramaFragmentImpl;
import org.microg.gms.maps.mapbox.StreetViewPanoramaViewImpl;
import org.microg.gms.maps.mapbox.model.BitmapDescriptorFactoryImpl;
import org.microg.gms.maps.mapbox.utils.MapContext;
import org.microg.gms.maps.mapbox.utils.MultiArchLoader;

@Keep
public class CreatorImpl extends ICreator.Stub {
Expand Down Expand Up @@ -68,8 +71,13 @@ public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() {

@Override
public void initV2(IObjectWrapper resources, int flags) {
BitmapDescriptorFactoryImpl.INSTANCE.initialize(ObjectWrapper.unwrapTyped(resources, Resources.class), null);
//ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources));
Resources mapResources = ObjectWrapper.unwrapTyped(resources, Resources.class);
ClassLoader moduleClassLoader = CreatorImpl.class.getClassLoader();
if (moduleClassLoader == null) {
throw new IllegalStateException("Mapbox backend class loader is not available");
}
BitmapDescriptorFactoryImpl.INSTANCE.initialize(mapResources, null);
LibraryLoader.setLibraryLoader(new MultiArchLoader(moduleClassLoader));
Log.d(TAG, "initV2 " + flags);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import com.google.android.gms.maps.internal.*
import com.google.android.gms.maps.model.*
import com.google.android.gms.maps.model.CircleOptions
import com.google.android.gms.maps.model.internal.*
import com.mapbox.mapboxsdk.LibraryLoader
import com.mapbox.mapboxsdk.Mapbox
import com.mapbox.mapboxsdk.R
import com.mapbox.mapboxsdk.camera.CameraUpdate
Expand All @@ -60,7 +59,6 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.location.engine.*
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
import org.microg.gms.maps.mapbox.model.*
import org.microg.gms.maps.mapbox.utils.MultiArchLoader
import org.microg.gms.maps.mapbox.utils.toGms
import org.microg.gms.maps.mapbox.utils.toMapbox
import java.util.concurrent.atomic.AtomicBoolean
Expand Down Expand Up @@ -130,7 +128,6 @@ class GoogleMapImpl(context: Context, var options: GoogleMapOptions) : AbstractG

init {
BitmapDescriptorFactoryImpl.initialize(mapContext.resources, context.resources)
LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context))
runOnMainLooper {
Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import android.view.LayoutInflater
import org.microg.gms.common.Constants
import java.io.File

class MapContext(private val context: Context) : ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY)) {
class MapContext(private val context: Context) : ContextWrapper(createModuleContext(context)) {
private var layoutInflater: LayoutInflater? = null
private val appContext: Context
get() = context.applicationContext ?: context
Expand Down Expand Up @@ -76,6 +76,10 @@ class MapContext(private val context: Context) : ContextWrapper(context.createPa
}

companion object {
private fun createModuleContext(context: Context): Context {
return context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY)
}

val TAG = "GmsMapContext"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,17 @@
package org.microg.gms.maps.mapbox.utils

import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.util.Log
import com.mapbox.mapboxsdk.LibraryLoader
import org.microg.gms.common.Constants
import org.microg.gms.common.PackageUtils
import java.io.*
import java.util.zip.ZipFile
import dalvik.system.BaseDexClassLoader

class MultiArchLoader(private val mapContext: Context, private val appContext: Context) : LibraryLoader() {
class MultiArchLoader(private val moduleClassLoader: ClassLoader) : LibraryLoader() {
@SuppressLint("UnsafeDynamicallyLoadedCode")
override fun load(name: String) {
try {
val otherAppInfo = mapContext.packageManager.getApplicationInfo(appContext.packageName, 0)
var primaryCpuAbi = ApplicationInfo::class.java.getField("primaryCpuAbi").get(otherAppInfo) as String?
if (primaryCpuAbi == "armeabi") {
primaryCpuAbi = "armeabi-v7a"
}
if (primaryCpuAbi != null) {
val path = "lib/$primaryCpuAbi/lib$name.so"
val cacheFile = File("${appContext.cacheDir.absolutePath}/.gmscore/$path")
cacheFile.parentFile?.mkdirs()
val cacheFileStamp = File("${appContext.cacheDir.absolutePath}/.gmscore/$path.stamp")
val cacheVersion = kotlin.runCatching { cacheFileStamp.readText() }.getOrNull()
// TODO: Use better version indicator
val mapVersion = PackageUtils.versionName(mapContext, Constants.GMS_PACKAGE_NAME)
val apkFile = File(mapContext.packageCodePath)
if (!cacheFile.exists() || cacheVersion == null || cacheVersion != mapVersion) {
val zipFile = ZipFile(apkFile)
val entry = zipFile.getEntry(path)
if (entry != null) {
copyInputStream(zipFile.getInputStream(entry), FileOutputStream(cacheFile))
} else {
Log.d(TAG, "Can't load native library: $path does not exist in $apkFile")
}
cacheFileStamp.writeText(mapVersion.toString())
}
Log.d(TAG, "Loading $name from ${cacheFile.getPath()}")
System.load(cacheFile.absolutePath)
findLibrary(name)?.let { path ->
Log.d(TAG, "Loading $name from $path")
System.load(path)
return
}
} catch (e: Exception) {
Expand All @@ -65,17 +37,8 @@ class MultiArchLoader(private val mapContext: Context, private val appContext: C
System.loadLibrary(name)
}

@Throws(IOException::class)
private fun copyInputStream(inp: InputStream, out: OutputStream) {
val buffer = ByteArray(1024)
var len: Int = inp.read(buffer)
while (len >= 0) {
out.write(buffer, 0, len)
len = inp.read(buffer)
}

inp.close()
out.close()
private fun findLibrary(name: String): String? {
return (moduleClassLoader as? BaseDexClassLoader)?.findLibrary(name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you verified this in a multi-arch environment?

That is, when the app using the play-services-maps library is build for a different architecture than the GMS package is installed at. The easiest way to test is to force install any app using maps as armeabi-v7a on a device that is arm64-v8a (most devices today). You can do this using adb install --abi armeabi-v7a target.apk

}

companion object {
Expand Down