3

We are using Carto Xamarin Mobile SDK to develop app with offline maps support. It works fine until user does not try to resume application after it has been disposed. Activity creation (activity uses carto package manager) crashes with exception:

Carto.PackageManager.CartoPackageManager.CartoPackageManager(string source, string dataFolder)<01980a2dae7148abb92e6b982667f448>:0
App.Droid.OfflineMaps.AndroidMapPackageManager.AndroidMapPackageManager()<76ae23b9271c407d865ebb6162639870>:0
App.Droid.Plugins.MapDownloader.Plugin.<>c.<Load>b__0_0()<76ae23b9271c407d865ebb6162639870>:0
MvvmCross.Platform.IoC.MvxSimpleIoCContainer.<>c__DisplayClass33_0<TInterface>.<RegisterSingleton>b__0()<4ddde23419c5494288c799fcdbb0f189>:0
MvvmCross.Platform.IoC.MvxSimpleIoCContainer.ConstructingSingletonResolver.Resolve()<4ddde23419c5494288c799fcdbb0f189>:0
MvvmCross.Platform.IoC.MvxSimpleIoCContainer.InternalTryResolve(Type type, MvxSimpleIoCContainer.IResolver resolver, ref object resolved
App.Core.ViewModels.Blocks.Maps.Offline.MapDownloaderOwnerViewModel.EnableMapDownloader(City city)<d6cca792b401420d922bc024

Here on line 105 you can see where exception is originally thrown.

In the regular entering page it works fine. PackageManager request is happening in the ctor of the page ViewModel via:

 Mvx.Resolve<MapDownloadsManager>(); // It receivs as injection platform-dependent packageManager

It seems that the problem is in the database path. We are generating the folder name that then passed to the CartoPackageManager constructor in the following way:

 private static string CreateFolder(string folderPath)
        {

        var folder = GetDocumentDirectory(folderPath);

        if (!Directory.Exists(folder))
        {
            Directory.CreateDirectory(folder);
        }

        return folder;
    }

    private static string GetDocumentDirectory(string withFolder = null)
    {
        var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

        return withFolder == null ? documents : Path.Combine(documents, withFolder + "/");
    }

Do you have any ideas where the source of the problem could be?

P.S.: Carto SDK v 4.0.2, MvvmCross 4.4.0, unfortunately can't update to the newer now.

After some research I have spotted that task queue is reset, now supposing that app actually crashes here in source code:

 std::string taskDbFileName = "tasks_v1.sqlite";
        try {
            _taskQueue = std::make_shared<PersistentTaskQueue>(createLocalFilePath(taskDbFileName));
        }
        catch (const std::exception& ex) {
            //This looks like: Error while constructing PackageManager: Package encryption keys do not match, trying to remove
            Log::Errorf("PackageManager: Error while constructing PackageManager::PersistentTaskQueue: %s, trying to remove...", ex.what());
            _taskQueue.reset();
            utf8_filesystem::unlink(taskDbFileName.c_str());
            try {
                _taskQueue = std::make_shared<PersistentTaskQueue>(createLocalFilePath(taskDbFileName));
            }
            catch (const std::exception& ex) {
                **throw FileException("Failed to create/open package manager task queue database", taskDbFileName); //App gets here.**
            }
        }

Initialization of package manager:

 public class AndroidMapPackageManager : PackageManagerListener, IPackageManger
    {
        private readonly CartoPackageManager _packageManager;

        public AndroidMapPackageManager()
        {
            var folder = CreateFolder(OfflineMapStrings.MapsFolderName); // /data/user/0/com.app.cityguide/files/mapmap2/

 _packageManager =
                    new CartoPackageManager(OfflineMapsStrings.PackageManagerSource, folder)
                    {
                        PackageManagerListener = this
                    };
       }
}

I am starting it just after the constructor worked after subscription to the listener events by other class. And, frankly saying, I never stop it. Do I need it?

With FIllRam Repoductivity is 100%. I used debug mode with no background allowed and now I tryed Ram Filler and result is same.

License issues:

05-25 12:41:41.091 26101 26101 E carto-mobile-sdk: CartoPackageManager: RegisterLicense not called, using random key for package encryption!
05-25 12:41:41.094 26101 26101 E carto-mobile-sdk: PackageManager: Error while constructing PackageManager: Package encryption keys do not match, trying to remove
Oleg Kosuakiv
  • 174
  • 2
  • 15
  • That's on Android, not iOS? The path should be same in all cases, but without having enough code to see full app lifecycle and replicate the issue, it is very hard to tell anything here. – JaakL May 22 '18 at 16:18
  • @JaakL, Yes, it is on Android. However, from your glance, does path generation looks okay? If so, I suggest I will have to look through carto sources, maybe there can be some key – Oleg Kosuakiv May 22 '18 at 20:14
  • @JaakL, can you please watch edits below P.S. section ? – Oleg Kosuakiv May 23 '18 at 07:53
  • Path generation looks fine, I see you've even used the same logic that is in our sample apps. However, I am not able to reproduce the issue with ram filler apps (these should dispose background apps). Could you provide more detailed code samples or steps to reproduce? – Nikitah May 23 '18 at 08:12
  • Actually, I don't have any idea which snippets can I attach more... – Oleg Kosuakiv May 23 '18 at 13:09
  • How and where do you initialize PackageManager? Where do you start and stop it? Could you provide the full path you're giving PackageManager? Can you easily reproduce the issue when filling ram with with https://play.google.com/store/apps/details?id=me.empirical.android.application.fillmemory&hl=en ? – Nikitah May 23 '18 at 13:24
  • @Nikitah, thanks for ideas. I will add additional info to question – Oleg Kosuakiv May 23 '18 at 13:52
  • Thanks for the additional samples. Yes, the database connection can get locked if you never close it. I advise you `.Start()` your packagemanager in `OnResume()` and `.Stop(false)` it in `OnPause()` if you don't need background download. – Nikitah May 24 '18 at 10:16
  • @Nikitah, Researched more and found some details in source code about encryption key. I have added them to the question. please take a look. – Oleg Kosuakiv May 25 '18 at 10:10
  • Thanks, I'll look into it. In the meantime: `RegisterLicense not called`. Why aren't you registering your license? – Nikitah May 26 '18 at 15:04
  • @Nikitah, We do this in SplashActivity.OnCreate(Bundle): MapView.RegisterLicense(CartoApiKey, this); BTW, I have an idea: maybe while restoring the application splash activity is not shown and that is why app crashes. I need to check it. – Oleg Kosuakiv May 29 '18 at 09:54
  • That can absolutely be the case. All initial configuration should be done in the `Application` class: https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class – Nikitah May 29 '18 at 10:41
  • @Nikitah, Thanks, moving registering of license did a trick! – Oleg Kosuakiv May 29 '18 at 14:10

1 Answers1

0

The problem was that I was registering license key in SplashActivity. But, after resuming splash activity is not shown and, obviously, Registering of the license key was not performed. I have moved it to the custom application class and it worked:

public class CustomApplication : Application
{
        public override void OnCreate()
        {
            base.OnCreate();
            MapView.RegisterLicense(CartoApiKey, this);
        }
}
Oleg Kosuakiv
  • 174
  • 2
  • 15