My app that uses Google Maps SDK (v2) just started crashing with this exception:
Process: com.currentlocation.android, PID: 7328
java.lang.ArrayIndexOutOfBoundsException: length=1; index=12
at com.google.maps.api.android.lib6.gmm6.vector.ct.<init>(:com.google.android.gms.dynamite_mapsdynamite@201216081@20.12.16 (120400-0):9)
at com.google.maps.api.android.lib6.gmm6.vector.cv.a(:com.google.android.gms.dynamite_mapsdynamite@201216081@20.12.16 (120400-0):23)
at com.google.maps.api.android.lib6.gmm6.util.m.run(:com.google.android.gms.dynamite_mapsdynamite@201216081@20.12.16 (120400-0):14)
at java.lang.Thread.run(Thread.java:919)
In the v3 beta SDK, the stack trace is:
2020-04-23 15:59:06.064 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example, PID: 22717
java.lang.ArrayIndexOutOfBoundsException: length=1; index=12
at com.google.android.libraries.maps.bv.zzbs.<init>(ZoomTable.java:24)
at com.google.android.libraries.maps.bv.zzbv.zza(ZoomTableQuadTree.java:57)
at com.google.android.libraries.maps.br.zzd.zza(Unknown Source:4)
at com.google.android.libraries.maps.hi.zzas.zza(Suppliers.java:7)
at com.google.android.libraries.maps.br.zza.zzh(SharedMapComponentImpl.java:58)
at com.google.android.libraries.maps.gu.zzat.zza(RendererFactoryImpl.java:88)
at com.google.android.libraries.maps.it.zzav.zza(GoogleMapImpl.java:59)
at com.google.android.libraries.maps.it.zzci.zza(MapFragmentDelegateImpl.java:3)
at com.google.android.libraries.maps.it.zzcg.zza(MapFragmentDelegateImpl.java:15)
at com.google.android.libraries.maps.SupportMapFragment$zza.onCreateView(SupportMapFragment.java:15)
at com.google.android.gms.dynamic.zae.zaa(com.google.android.gms:play-services-base@@17.1.0:4)
at com.google.android.gms.dynamic.DeferredLifecycleHelper.zaa(com.google.android.gms:play-services-base@@17.1.0:9)
at com.google.android.gms.dynamic.DeferredLifecycleHelper.onCreateView(com.google.android.gms:play-services-base@@17.1.0:25)
at com.google.android.libraries.maps.SupportMapFragment.onCreateView(SupportMapFragment.java:34)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:310)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1185)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2617)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2569)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2722)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:336)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1186)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2222)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1995)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1951)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2621)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2569)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2722)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:336)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1186)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2617)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2569)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1432)
at android.app.Activity.performStart(Activity.java:7848)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3294)
2020-04-23 15:59:06.064 E/AndroidRuntime: at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
What is the cause?
Seems in every app Google Map creates ZoomTables.data file.
This file was malformed, malformed version of it that could be downloaded from comment. To reproduce the issue remove ZoomTables.data from the app packages on the device and insert malformed one. The app should crash.
Currently, the issue was solved on google's side, but the apps still contain a cached version of that data file. To fix the issue we should remove that file right on the app start in Application onCreate Method.
private void fixGoogleMapBug() {
try {
SharedPreferences hasFixedGoogleBug154855417 = getSharedPreferences("google_bug_154855417", Context.MODE_PRIVATE);
if (!hasFixedGoogleBug154855417.contains("fixed")) {
File corruptedZoomTables = new File(getFilesDir(), "ZoomTables.data");
File corruptedSavedClientParameters = new File(getFilesDir(), "SavedClientParameters.data.cs");
File corruptedClientParametersData =
new File(
getFilesDir(),
"DATA_ServerControlledParametersManager.data."
+ getBaseContext().getPackageName());
File corruptedClientParametersDataV1 =
new File(
getFilesDir(),
"DATA_ServerControlledParametersManager.data.v1."
+ getBaseContext().getPackageName());
corruptedZoomTables.delete();
corruptedSavedClientParameters.delete();
corruptedClientParametersData.delete();
corruptedClientParametersDataV1.delete();
hasFixedGoogleBug154855417.edit().putBoolean("fixed", true).apply();
}
} catch (Exception e) {
}
}
Update 1
I've updated workaround, base on the latest google developers comment:
The workarounds provided here covers all available flavors and versions of our SDKs for Android. To clarify further (in case you released an earlier version of the workaround that did not delete as many files):
Applications that use Maps Android SDK v2 should only need to delete one file: ZoomTables.data. Applications that use Maps Android SDK v3 beta should only need to delete one file, either DATA_ServerControlledParametersManager.data.v1. + getBaseContext().getPackageName()) or DATA_ServerControlledParametersManager.data. + getBaseContext().getPackageName())
For Android, multiple developers mentioned a workaround consisting in deleting the ZoomTable.data file directly from their application. After review, this fix seems safe, and you could try it in your application.
Please refer to https://issuetracker.google.com/154855417#comment179
If you want your users to continue using your app without re-installing, The sample code is copy-pasted here for your convenience. In Application.onCreate():
SharedPreferences googleBug = getSharedPreferences("google_bug_154855417", Context.MODE_PRIVATE);
if (!googleBug.contains("fixed")) {
File corruptedZoomTables = new File(getFilesDir(), "ZoomTables.data");
corruptedZoomTables.delete();
googleBug.edit().putBoolean("fixed", true).apply();
}
reference: Google Maps SDK is crashing -- partially resolved
This solution worked for me
First open "App Info"
Choose "Storage"
Click "Clear data"
Open app again and check if the issue fixed.
Below are suggestions just to help your customers.
Send an email to your all users for the inconvenience and describe them the issue they faced and give them above mentioned steps to resolve their issue.
You can also send Push Notification to all your users with Firebase Push Notifications, if your app have the push notifications service.
Screenshots demonstration:
https://issuetracker.google.com/issues/154855417#comment509
The updates to Google Play Services to fix the crash has been published to all devices with Google Play Services version 17.4.55 and newer. There is no change to the version number of Google Play Services on the device after the update is installed. No action is required from developers or end users to receive the updated Maps module; however, developers can verify that the module is present on a given device with the following adb command:
adb shell dumpsys activity provider com.google.android.gms.chimera.container.GmsModuleProvider
You should see the line Module Set ID: maps listed in the Module Sets section.
Module Set ID: maps, Module Set Version: 2015120015120000
The crash rates of Maps SDK for Android v2 are back to normal.
As of now, if you have not updated your app with the client-side code workarounds mentioned below, you do not need to take further action.
If you have already updated your app with the workarounds, you can remove the workaround in a subsequent update of your app (but keeping the workaround is safe).
The productive version was fixed (on google's side) but if you still have problems with your emulator you have to run the following code only once.
The recommended placement for the code is in Application.onCreate():
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fixGoogleMapBugTemp() //TODO: Then clean this line
// ...
}
/**
* Observation: Invoke this method only once
*/
private fun fixGoogleMapBugTemp() {
val googleBug = getSharedPreferences("google_bug_154855417", Context.MODE_PRIVATE)
if (!googleBug.contains("fixed")) {
val corruptedZoomTables = File(filesDir, "ZoomTables.data");
corruptedZoomTables.delete();
googleBug.edit().putBoolean("fixed", true).apply();
}
}
Workaround: Clear application data (not just the cache).
Note: A copy of the problematic file from the app packages on the device if anyone needs it for repro.
GL
Drawbacks of solutions above:
Drawbacks of my solution:
My solution catches the Exception thrown by the Maps SDK, call this in onCreate of the Application class:
public static void catchGoogleMapsException(final Context context)
{
final Thread.UncaughtExceptionHandler defaultHandler =
Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(
(@NonNull final Thread thread, @NonNull final Throwable ex) ->
{
if (thread.getName().contains("ZoomTableManager"))
{
new File(context.getFilesDir(), "ZoomTables.data").delete();
Log.w("Maps Bug 154855417", "Caught exception and deleted ZoomTables.data");
}
else
if (defaultHandler!=null)
defaultHandler.uncaughtException(thread, ex);
else
throw new RuntimeException(
"No default uncaught exception handler.", ex);
});
}
This is working code for Xamarin. You need to install Xamarin.Essentials nuget package.
if (!Preferences.Get("google_bug_fixed", false))
{
var corruptedZoomTables = new File(FileSystem.AppDataDirectory, "ZoomTables.data");
corruptedZoomTables.Delete();
Preferences.Set("google_bug_fixed", true);
}
You should call the follow method on the onCreate of your Android app to avoid the crash.
private fun clearCorruptedGMapsPreference() {
try {
val sharedPreferences = getSharedPreferences("google_bug_154855417", Context.MODE_PRIVATE)
if (!sharedPreferences.contains("fixed")) {
val corruptedZoomTables = File(filesDir, "ZoomTables.data")
val corruptedSavedClientParameters = File(filesDir, "SavedClientParameters.data.cs")
val corruptedClientParametersData = File(filesDir, "DATA_ServerControlledParametersManager.data.${packageName}")
val corruptedClientParametersDataV1 = File(filesDir, "DATA_ServerControlledParametersManager.data.v1.${packageName}")
corruptedZoomTables.delete()
corruptedSavedClientParameters.delete()
corruptedClientParametersData.delete()
corruptedClientParametersDataV1.delete()
sharedPreferences.edit().putBoolean("fixed", true).apply()
}
} catch (exception: Exception) {
LogUtil.e(this@CourierApplication::class.java.name, "An error has happened. Error: ".plus(exception.cause?.message
?: ""))
}
}
Workaround suggested will only work one time:
I suggest to send a silent push notification to your app about Google Map Zoom Data Corrupted or make an API call to check the status of the Google Map Zoom Data. If you think this as un-necessary server call every time, you can either use push notification to trigger this logic or integrate with one of your existing calls where you check status of your servers. Leaving this to your app specific logics.Doing so, if Google Maps again throws this error you can re-trigger your work-around.
If server call, this will reset ZoomData for all your users. If push-notifications, you can send notifications to some users.
fun receivedPushNotificationZoomDataCorrupted() {
try {
val corruptedZoomTables = File(filesDir, "ZoomTables.data")
val corruptedSavedClientParameters = File(filesDir, "SavedClientParameters.data.cs")
val corruptedClientParametersData = File(filesDir, "DATA_ServerControlledParametersManager.data.v1.${packageName}")
corruptedZoomTables.delete()
corruptedSavedClientParameters.delete()
corruptedClientParametersData.delete()
}
} catch (exception: Exception) {
}
}