play-games-plugin-for-unity icon indicating copy to clipboard operation
play-games-plugin-for-unity copied to clipboard

Internal Error with saving and loading cloud saves

Open ChibiPhoenixGithub opened this issue 2 years ago • 16 comments

Hello,

On my test devices cloud saving and loading used to work, but now I am receiving 'internal error' messages. Cloud saving and loading still works fine for my other users and I did not change my code regarding cloud saving and loading in any way. Since this is happening only on my personal test devices, I would like to tackle the issue before I fully release my app, so future users won't have to deal with it.

I've looked around to find more information regarding the internal error and as I understand the Android Logcat might provide more details. The moment my app tries to either save or load the cloud file I get the following log:

20210901_screenshot_logcat

I am still rather new at programming, can someone more knowledgable help out or is this a bug with the current version of the GooglePlayServices plugin?

ChibiPhoenixGithub avatar Sep 01 '21 07:09 ChibiPhoenixGithub

Hi @ChibiPhoenixGithub, Would it be possible to share logcats/bug reports with us? Preferably link to a Google Drive folder but, please, don't accept access request unless it from @google.com email addresses.

See https://developer.android.com/studio/debug/bug-report for the guid on capture and read bug reports.

smile616 avatar Sep 01 '21 10:09 smile616

@smile616 Alright, I think I got it, I just made a bugreport while making my app hit the error (I limited the cloud saves attempts, since it was going absolutely insane on the query count)

I uploaded the dump file to Google Drive and I have a share URL available, is it possible to send a personal message on GitHub (or what is the usual way of doing things like this?)

ChibiPhoenixGithub avatar Sep 01 '21 11:09 ChibiPhoenixGithub

@ChibiPhoenixGithub I don't think there is a personal message on GitHub. Instead of share URL, paste private Drive link here. Then you will get a request to access it from a @google.com email addresses. Don't share unless request is from @google.com

smile616 avatar Sep 01 '21 11:09 smile616

thank you, @ChibiPhoenixGithub. You can disable the sharing for that file.

smile616 avatar Sep 01 '21 11:09 smile616

Thanks!

I also uploaded a logcat output (not sure if they differ, but just want to be thorough!) URL: https://drive.google.com/file/d/1FQj8FTktduny8qXdXq9f1x_KAFTwtJmW/view?usp=sharing

EDIT: Would it be relevant to also include the code responsible for calling the save / load?

EDIT2: Cleared up the topic a little by merging my comments ;-)

EDIT3: Not sure if I mentioned this, but it happens on both of my test devices (Samsung Galaxy Note9 and the Google Pixel 3)

ChibiPhoenixGithub avatar Sep 01 '21 11:09 ChibiPhoenixGithub

(JFYI, logcat is included in the bug report) you could unshare the logcat output now. Thank you!

Would it be relevant to also include the code responsible for calling the save / load?

Sure, that would be useful.

Not sure if I mentioned this, but it happens on both of my test devices (Samsung Galaxy Note9 and the Google Pixel 3)

Do you see the same 4002 error on both devices? And/Or the following in the logcat: Unable to open file: 09d86c4a-46af-4307-8200-af004778904 java.io.FileNotFoundException: open failed: ENOENT ?

Are you able to reproduce the issue straightway if you change the snapshot filename?

smile616 avatar Sep 01 '21 12:09 smile616

Yes, I did notice the same error message, it seemed really weird that it's giving a FileNotFoundException.

So far what I notice is that initially it correctly saves to the cloud, but after a small timeframe it will start throwing those errors. As soon as the errors happen, I am unable to do any saves.

I just added a zip with the code (sorry for the .txt format), (also shared the link with you) I removed the parts that are irrelevant for the cloud saving (like achievement related code, code to encrypt the files etc, since they don't have anything to do with actually using the API).

Good idea with regards to the filename, did not think of that very simple idea yet! I will give it a whirl and see if it still happens, I will report back!

ChibiPhoenixGithub avatar Sep 01 '21 12:09 ChibiPhoenixGithub

thank you, @ChibiPhoenixGithub !

smile616 avatar Sep 01 '21 12:09 smile616

Alright! So I tried it with different filenames and sadly... it still happens :( I uploaded the logcat from both devices and send you the link.

ChibiPhoenixGithub avatar Sep 01 '21 13:09 ChibiPhoenixGithub

received. Thank you for the update! (I will be looking into the issue tomorrow and day after tomorrow)

smile616 avatar Sep 01 '21 13:09 smile616

Thanks!

ChibiPhoenixGithub avatar Sep 01 '21 14:09 ChibiPhoenixGithub

@ChibiPhoenixGithub

From the firs look it seem that the issue is triggered by multiple changes to the same save game slot that happen before change is saved.

For example there could be a following sequence of calls: SaveToCloud<ProfileDataModel>(...) OpenCloudSave<ProfileDataModel>(OnSaveResponse<ProfileDataModel>, ...) SaveToCloud<ProfileDataModel>(...) OpenCloudSave<ProfileDataModel>(OnSaveResponse<ProfileDataModel>, ...) SaveToCloud<ProfileDataModel>(...) OpenCloudSave<ProfileDataModel>(OnSaveResponse<ProfileDataModel>, ...) SaveToCloud<ProfileDataModel>(...) OpenCloudSave<ProfileDataModel>(OnSaveResponse<ProfileDataModel>, ...) OnSaveResponse<ProfileDataModel>(...) platform.SavedGame.CommitUpdate(..., SaveCallback<ProfileDataModel>) OnSaveResponse<ProfileDataModel>(...) platform.SavedGame.CommitUpdate(..., SaveCallback<ProfileDataModel>) OnSaveResponse<ProfileDataModel>(...) platform.SavedGame.CommitUpdate(..., SaveCallback<ProfileDataModel>) OnSaveResponse<ProfileDataModel>(...) platform.SavedGame.CommitUpdate(..., SaveCallback<ProfileDataModel>) SaveCallback<ProfileDataModel>(...) AfterSave<ProfileDataModel>(...) and so on.

Effectively this would result in concurrent change agains same base. Ideally OpenCloudSave<ProfileDataModel> should be called until SaveCallback<ProfileDataModel>(...) is called. Same for the OpenCloudSave<SaveDataModel> and SaveCallback<SaveDataModel>.

I'd suggest adding isProfileUpdating, isSaveUpdating, isProfileUpdateNeeded, isSaveUpdateNeeded flags and use them as in the following example:

           public void SaveToCloud<T>( ....) 
           {
                ...
                if (typeof(T) == typeof(SaveDataModel))
                {
                   if (isSaveUpdating)
                   {
                        isSaveUpdateNeeded = true;
                        return;
                   }
                   isSaveUpdating = true;
                   GooglePlayServicesManager.Instance.OpenCloudSave<SaveDataModel>(OnSaveResponse<T>, errorCallback);
                }
                else if (typeof(T) == typeof(ProfileDataModel))
                {
                   if (isProfileUpdating)
                   {
                        isProfileUpdateNeeded = true;
                        return;
                   }
                   isProfileUpdating = true;
                    GooglePlayServicesManager.Instance.OpenCloudSave<ProfileDataModel>(OnSaveResponse<T>, errorCallback);
                }
                ....
                
                
              private void SaveCallback<T>(...) 
              {
                  if (typeof(T) == typeof(SaveDataModel))
                {
                   isSaveUpdating = false;
                   if (isSaveUpdateNeeded)
                   {
                        isSaveUpdateNeeded = false;
                        SaveToCloud<SaveDataModel>...
                   }
                }
                else if (typeof(T) == typeof(ProfileDataModel))
                {
                   isProfileUpdating = false;
                   if (isProfileUpdateNeeded)
                   {
                        isProfileUpdateNeeded = false;
                        SaveToCloud<ProfileDataModel>...
                   }
                }
                ...
                

(note, you may need similar check in OnSaveResponse for case when status != SavedGameRequestStatus.Success)

smile616 avatar Sep 03 '21 17:09 smile616

@smile616 Ok, that definitely should not happen. The profile file should only ever update if the user changes a setting (eg. screen resolution), it should definitely not be called this many times. Your example is very helpful, thanks! Now I know what to look into, I can work on fixing the issue :-)

Can you explain to me how you found the issue? I would like to be able to debug these sort of issues on my own in the future.

EDIT: Sadly the error still occurs... I'm going to re-check my code to make sure it does not spam calls, will come back with the results

EDIT2: Ok, so far so good on a build I install through .apk, now to see if everything is stable when installing through the Google Play Store.

EDIT3: Seems stable so far, will keep an eye on it. If it occurs again I will post an update

ChibiPhoenixGithub avatar Sep 04 '21 06:09 ChibiPhoenixGithub

@ChibiPhoenixGithub

Can you explain to me how you found the issue?

In general when code is asynchronous, some debug output could reveal the actual sequence of the events.

smile616 avatar Sep 06 '21 12:09 smile616

@smile616 I think I have narrowed it down. It seems that it happened because I overlooked what could happen opposed to what I expected to happen. I had my profile container (the one holding the profiledata through the scenes), update the cloud save on EVERY update to it's data (oops). I have reworked that part, it now only calls the actual SaveToCloud, when it makes sense to do so... It also called this on loading, since all the fields were being updated... which explains the "SaveToCloud", "SaveToCloud", "SaveToCloud"....

Your solution definitely mitigated the issue, but the spam was so ferocious that it still ended up breaking it.

Don't know if it would be possible, but would it make sense for the OpenCloudSave to return an exception if it is called while it is still open/opening etc? Or maybe a property to indicate it is 'busy'

ChibiPhoenixGithub avatar Sep 07 '21 07:09 ChibiPhoenixGithub

@ChibiPhoenixGithub

Thank you for the update. We are considering some changes and updated examples that will make the API less error prone.

smile616 avatar Sep 08 '21 09:09 smile616