Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed restarting not working properly #7068

Merged
merged 1 commit into from
Sep 11, 2021

Conversation

litetex
Copy link
Member

@litetex litetex commented Sep 6, 2021

What is it?

  • Bugfix (user facing)
  • Feature (user facing)
  • Codebase improvement (dev facing)
  • Meta improvement to the project (dev facing)

Description of the changes in your PR

The current method

/**
* Finish this <code>Activity</code> as well as all <code>Activities</code> running below it
* and then start <code>MainActivity</code>.
*
* @param activity the activity to finish
*/
public static void restartApp(final Activity activity) {
NewPipeDatabase.close();
activity.finishAffinity();
final Intent intent = new Intent(activity, MainActivity.class);
activity.startActivity(intent);
}
doesn't seem to work as expected. It fails to restart the app completely which causes invalid states when e.g. migrating the database and results in an appcrash.

Note: This introduces a new external library: process-phoenix

Before/After Screenshots/Screen Record

  • Before:
NewPipeCrashOnImport.mp4

Note: ACRA fails to open, may be an additional problem (could be #5222)

Also note that it migrates the settings after the app crashes as seen in the log 😆:
NewPipeCrashOnImport.log

  • After:
NoNewPipeCrashOnImport.mp4

NoNewPipeCrashOnImport.log

APK testing

The APK can be found by going to the "Checks" tab below the title. On the left pane, click on "CI", scroll down to "artifacts" and click "app" to download the zip file which contains the debug APK of this PR.

Due diligence

@litetex litetex mentioned this pull request Sep 6, 2021
7 tasks
@XiangRongLin
Copy link
Collaborator

The readme of the library states

This should only be used for things like fundamental state changes in your debug builds (e.g., changing from staging to production).

So is it safe to use in release/production use? Even if it is safe, should it be used?

@litetex
Copy link
Member Author

litetex commented Sep 7, 2021

This should only be used for things like fundamental state changes in your debug builds (e.g., changing from staging to production).

I think this was written wrongly by the author. I think he refers to state changes in the app.

So is it safe to use in release/production use? Even if it is safe, should it be used?

I don't know that but it's certainly better than the current solution of right out crashing 😆

It's been around since 2016 has currently 5 issues and 1.5k stars so looks pretty solid to me.

Maybe someone could test this with an production grade APK because I'm unable to build one (no documentation for that; running gradlew.bat assemble results in an unsigned apk that can't be installed).

@XiangRongLin
Copy link
Collaborator

Maybe someone could test this with an production grade APK because I'm unable to build one (no documentation for that; running gradlew.bat assemble results in an unsigned apk that can't be installed).

You are missing the flavour, which should be build. In this case release and not debug so =>
gradlew.bat assembleRelease
The fact that it's unsigned should not matter


Did you check if storing the import/export path on import is still working. Because since https://github.com/TeamNewPipe/NewPipe/pull/6531/files it relies on the app being closed orderly, which may or may not happen with this library.
https://github.com/TeamNewPipe/NewPipe/blob/dev/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java#L271


I don't know that but it's certainly better than the current solution of right out crashing 😆

Rather than that the root cause should be found instead of workaround, especially if a new library has to be introduced.

So I took a closer look and the root cause has nothing to do with the restart.
Apparently someone changed the type of the setting behind show_search_suggestions. If you set a breakpoint here and look at the settings file when importing an older backup, you can see that the type is a boolean and not a Set<String>

If you create a new export and import that one, it works.

Since the breaking change was already made, there is nothing to be done there.
Instead the import process has to throw away the key if it is not the expected type of Set

@XiangRongLin
Copy link
Collaborator

If the change was recent and not released yet, then it can be solved "nicely" by using a different key and we don't need the extra logic to throw away the key

@XiangRongLin
Copy link
Collaborator

@TobiGr
Copy link
Member

TobiGr commented Sep 9, 2021

Can someone check which SettingMigrations are run after importing and at restart? Are they run at all? If not, that is the root cause of the problem.

@TobiGr TobiGr added the bug Issue is related to a bug label Sep 9, 2021
@TobiGr
Copy link
Member

TobiGr commented Sep 9, 2021

Looks like we do not run the settings migrations after importing the database. I was not able to reproduce the bug before, so I don't know it this addition solves the problem. Please test it:

diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
index 6e7e759326..21cf388789 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
@@ -240,6 +240,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
                     dialog.dismiss();
                     manager.loadSharedPreferences(PreferenceManager
                             .getDefaultSharedPreferences(requireContext()));
+                    SettingMigrations.initMigrations(requireContext(), false);
                     finishImport(importDataUri);
                 });
                 alert.show();

@litetex
Copy link
Member Author

litetex commented Sep 9, 2021

I think the comments are going into the wrong direction.
Reminder:
There is a method that says restartApp which fails to restart the app completely which in turn causes invalid states (like broken databases).

This PR is not about fixing a currently broken database migration.

@litetex
Copy link
Member Author

litetex commented Sep 9, 2021

There is also e.g. a Recaptcha cookie set from the preferences when initializing the downloader / app:

downloader.setCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY, prefs.getString(key, null));

Or other things like:

prefs.getBoolean(getString(R.string.download_thumbnail_key), true));

&& prefs.getBoolean(getString(R.string.show_image_indicators_key), false));

This is also not done currently when importing the settings.

@litetex
Copy link
Member Author

litetex commented Sep 9, 2021

@XiangRongLin

Did you check if storing the import/export path on import is still working

Still works 😄

  • Imported from Downloads
  • Copied the zip from Downloads to Documents
  • Import file explorer now opens the Downloads folder
  • Imported the zip from Documents
  • Import file explorer now opens the Documents folder

@XiangRongLin
Copy link
Collaborator

There is a method that says restartApp which fails to restart the app completely which in turn causes invalid states (like broken databases).

The crash in the video at top is caused by the change of the type of the of the show_search_suggestions setting.

As is said

If you create a new export and import that one, it works.


I think the comments are going into the wrong direction.

I went this direction, because I only had the information available that the app is crashing when searching, which i took from the videos.

There is also e.g. a Recaptcha cookie ...

This changes some things, that I will have to look at

@litetex
Copy link
Member Author

litetex commented Sep 9, 2021

I think my comment at #7066 (comment) was a bit misleading... Sorry.
I edited it so that it now includes (but not only limited to them)

@Stypox
Copy link
Member

Stypox commented Sep 10, 2021

Can you make a followup PR before releasing 0.21.10 and use a different name for the key

Well no, I made a migration so that the old boolean value is not discarded but is instead transformed into the Set. This should happen before that preference is ever accessed, i.e. on app startup. The restart process should trigger a normal app startup where settings migrations are run. Does this happen with this PR @litetex? From a little bit of testing it seems to work.

@litetex
Copy link
Member Author

litetex commented Sep 10, 2021

@Stypox

Does this happen with this PR @litetex?

Yes it does.
As seen in the log files (above).

The corresponding parts:

  • current behavior
...
D/OpenGLRenderer: endAllActiveAnimators on 0xb91a5630 (RippleDrawable) with handle 0xbddb3cf0
D/OpenGLRenderer: endAllActiveAnimators on 0xb91b86b0 (RippleDrawable) with handle 0xbddb7130
D/CompatibilityChangeReporter: Compat change id reported: 119147584; UID 10121; state: DISABLED
D/MainFragment@3ccf87c: TabsManager.SavedTabsChangeListener: onTabsChanged called, isResumed = false
W/SQLiteLog: (28) file unlinked while open: /data/user/0/org.schabi.newpipe.debug/databases/newpipe.db
D/LeakCanary: Watching instance of androidx.fragment.app.FragmentManagerViewModel (androidx.fragment.app.FragmentManagerViewModel received ViewModel#onCleared() callback) with key 7f44b25e-a1f9-48f4-8b49-80a2dfc9a962
    Watching instance of leakcanary.internal.ViewModelClearedWatcher (leakcanary.internal.ViewModelClearedWatcher received ViewModel#onCleared() callback) with key 9a9e519f-5a88-43f0-9d9e-854844270a3e
D/LeakCanary: Watching instance of androidx.lifecycle.ReportFragment (androidx.lifecycle.ReportFragment received Fragment#onDestroy() callback) with key 014bc304-5997-4fad-9dbc-cfd1838a8dca
    Watching instance of org.schabi.newpipe.MainActivity (org.schabi.newpipe.MainActivity received Activity#onDestroy() callback) with key faefc784-51ec-40b3-9774-2ee729b0fa85
D/LeakCanary: Watching instance of android.widget.RelativeLayout (org.schabi.newpipe.fragments.BlankFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks)) with key e436d44b-eacd-4cec-85ca-fed089099601
D/LeakCanary: Watching instance of android.widget.RelativeLayout (org.schabi.newpipe.fragments.list.kiosk.DefaultKioskFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks)) with key 31c7f59b-c0e3-400c-80b5-dbe51baeeeca
    Watching instance of android.widget.RelativeLayout (org.schabi.newpipe.fragments.MainFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks)) with key 47e9a72c-dc51-4807-8b18-a6a2215df07e
    Watching instance of androidx.loader.app.LoaderManagerImpl$LoaderViewModel (androidx.loader.app.LoaderManagerImpl$LoaderViewModel received ViewModel#onCleared() callback) with key 25abce9e-b754-4347-9246-12de934c6c74
    Watching instance of leakcanary.internal.ViewModelClearedWatcher (leakcanary.internal.ViewModelClearedWatcher received ViewModel#onCleared() callback) with key c6827afe-ff85-4095-bf5a-d5a05d5f07a9
D/LeakCanary: Watching instance of androidx.loader.app.LoaderManagerImpl$LoaderViewModel (androidx.loader.app.LoaderManagerImpl$LoaderViewModel received ViewModel#onCleared() callback) with key d6b0e3ac-e398-43c0-9be6-501b21b6a360
    Watching instance of leakcanary.internal.ViewModelClearedWatcher (leakcanary.internal.ViewModelClearedWatcher received ViewModel#onCleared() callback) with key 11f78c54-2754-42a5-b6d9-ce6b5235f7d9
D/LeakCanary: Watching instance of org.schabi.newpipe.fragments.BlankFragment with key 60ac0b78-a155-4b90-bba2-af4e156d62a1
D/LeakCanary: Watching instance of org.schabi.newpipe.fragments.BlankFragment (org.schabi.newpipe.fragments.BlankFragment received Fragment#onDestroy() callback) with key f4d9f85d-d2fd-4ec8-9a9c-248462f117ca
D/LeakCanary: Watching instance of androidx.loader.app.LoaderManagerImpl$LoaderViewModel (androidx.loader.app.LoaderManagerImpl$LoaderViewModel received ViewModel#onCleared() callback) with key 77f1092e-051e-402f-9d1d-eba23af5ff64
D/LeakCanary: Watching instance of leakcanary.internal.ViewModelClearedWatcher (leakcanary.internal.ViewModelClearedWatcher received ViewModel#onCleared() callback) with key 4f6d7943-22a9-4087-a526-2421a3e949ad
D/LeakCanary: Watching instance of org.schabi.newpipe.fragments.list.kiosk.DefaultKioskFragment with key 0ca3f1e7-d221-4583-a585-fd72f7a93cc9
D/StateSaver: onDestroy() called with: savedState = [1606286191519 > /storage/emulated/0/Android/data/org.schabi.newpipe.debug/cache/state_cache/1606286191519.86.list]
D/LeakCanary: Watching instance of org.schabi.newpipe.fragments.list.kiosk.DefaultKioskFragment (org.schabi.newpipe.fragments.list.kiosk.DefaultKioskFragment received Fragment#onDestroy() callback) with key f8cf4de6-2fe4-473e-98d9-816d25829674
    Watching instance of org.schabi.newpipe.fragments.MainFragment with key eed04179-22b2-4621-8f80-a9dd7e952c52
D/LeakCanary: Watching instance of org.schabi.newpipe.fragments.MainFragment (org.schabi.newpipe.fragments.MainFragment received Fragment#onDestroy() callback) with key 8e7db7e5-03b1-40fe-9813-40cdad89407f
D/StateSaver: clearStateFiles() called
D/MainActivity: onCreate() called with: savedInstanceState = [null]
D/MainActivity: initFragments() called
D/StateSaver: clearStateFiles() called
D/InfoCache: trimCache() called
D/MainFragment@fef0b62: onCreate() called with: savedInstanceState = [null]
D/MainFragment@fef0b62: onViewCreated() called with: rootView = [android.widget.RelativeLayout{b77f0e3 V.E...... ......I. 0,0-0,0}], savedInstanceState = [null]
D/MainFragment@fef0b62: onTabSelected() called with: selectedTab = [com.google.android.material.tabs.TabLayout$Tab@68f2c5e]
D/MainFragment@fef0b62: setTitle() called with: title = [NewPipe]
...

Restart occurs around W/SQLiteLog: (28) file unlinked while open: /data/user/0/org.schabi.newpipe.debug/databases/newpipe.db however no migration are run in the followup.

  • behavior in this pr
...
D/OpenGLRenderer: endAllActiveAnimators on 0xb9ebefd0 (RippleDrawable) with handle 0xbf1321b0
D/OpenGLRenderer: endAllActiveAnimators on 0xb9eba750 (RippleDrawable) with handle 0xbf132e70
D/CompatibilityChangeReporter: Compat change id reported: 119147584; UID 10122; state: DISABLED
D/MainFragment@de3c505: TabsManager.SavedTabsChangeListener: onTabsChanged called, isResumed = false
W/SQLiteLog: (28) file unlinked while open: /data/user/0/org.schabi.newpipe.debug.fixrestart/databases/newpipe.db
Connected to process 5092 on device 'Pixel_3a_API_30_11.0 [emulator-5554]'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
D/ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.test.base.jar
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
I/MultiDex: VM with version 2.1.0 has multidex support
    Installing application
    VM has multidex support, MultiDex support library is disabled.
I/ACRA: ACRA is enabled for org.schabi.newpipe.debug.fixrestart, initializing...
I/class org.schabi.newpipe.App: This is a phoenix process! Aborting initialization of App[onCreate]
I/stetho: Listening on @stetho_org.schabi.newpipe.debug.fixrestart:phoenix_devtools_remote
D/libEGL: loaded /vendor/lib/egl/libEGL_emulation.so
D/libEGL: loaded /vendor/lib/egl/libGLESv1_CM_emulation.so
D/libEGL: loaded /vendor/lib/egl/libGLESv2_emulation.so
I/Process: Sending signal. PID: 4996 SIG: 9
Connected to process 5123 on device 'Pixel_3a_API_30_11.0 [emulator-5554]'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
D/ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.test.base.jar
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
    No Network Security Config specified, using platform default
I/MultiDex: VM with version 2.1.0 has multidex support
    Installing application
    VM has multidex support, MultiDex support library is disabled.
I/ACRA: ACRA is enabled for org.schabi.newpipe.debug.fixrestart, initializing...
D/class org.schabi.newpipe.settings.SettingMigrations: Migrating preferences from version 3 to 4
...

2x restart occurs. The first one kills the app completely.
While the second one performs a clean start which does the migrations.

Copy link
Member

@Stypox Stypox left a comment

Choose a reason for hiding this comment

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

Ok, thank you :-)

Copy link
Collaborator

@XiangRongLin XiangRongLin left a comment

Choose a reason for hiding this comment

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

Shouldn't the target branch be the release one instead of dev?

@TobiGr TobiGr changed the base branch from dev to release/0.21.10 September 11, 2021 10:51
@TobiGr
Copy link
Member

TobiGr commented Sep 11, 2021

yes.

@TobiGr TobiGr merged commit a288703 into TeamNewPipe:release/0.21.10 Sep 11, 2021
@litetex litetex deleted the fix-restart branch September 12, 2021 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue is related to a bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants