author | Jim Chen <nchen@mozilla.com> |
Thu, 11 May 2017 16:39:30 -0400 | |
changeset 357980 | 2458deaf60644dc8aaf1878b72ddc3c61b467507 |
parent 357979 | 11495bc7075515c06ea79d38c5c3d223304bccb7 |
child 357981 | 632e8d8dd0774748b3ad40776f73d309dbded9aa |
push id | 31808 |
push user | cbook@mozilla.com |
push date | Fri, 12 May 2017 12:37:49 +0000 |
treeherder | mozilla-central@030c0a7c8781 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | snorp |
bugs | 1362191 |
milestone | 55.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java @@ -5,17 +5,16 @@ package org.mozilla.gecko; import android.Manifest; import android.annotation.TargetApi; import android.app.DownloadManager; import android.content.ContentProviderClient; import android.os.Environment; -import android.os.Process; import android.support.annotation.NonNull; import android.support.annotation.UiThread; import org.mozilla.gecko.activitystream.ActivityStream; import org.mozilla.gecko.adjust.AdjustBrowserAppDelegate; import org.mozilla.gecko.annotation.RobocopTarget; import org.mozilla.gecko.AppConstants.Versions; import org.mozilla.gecko.DynamicToolbar.VisibilityTransition; @@ -762,16 +761,17 @@ public class BrowserApp extends GeckoApp "Menu:Remove", "LightweightTheme:Update", "Tab:Added", "Video:Play", "CharEncoding:Data", "CharEncoding:State", "Settings:Show", "Updater:Launch", + "Sanitize:Finished", "Sanitize:OpenTabs", null); EventDispatcher.getInstance().registerBackgroundThreadListener(this, "Experiments:GetActive", "Experiments:SetOverride", "Experiments:ClearOverride", "Favicon:Request", @@ -1562,16 +1562,17 @@ public class BrowserApp extends GeckoApp "Menu:Remove", "LightweightTheme:Update", "Tab:Added", "Video:Play", "CharEncoding:Data", "CharEncoding:State", "Settings:Show", "Updater:Launch", + "Sanitize:Finished", "Sanitize:OpenTabs", null); EventDispatcher.getInstance().unregisterBackgroundThreadListener(this, "Experiments:GetActive", "Experiments:SetOverride", "Experiments:ClearOverride", "Favicon:Request", @@ -1611,38 +1612,16 @@ public class BrowserApp extends GeckoApp mFormAssistPopup.destroy(); if (mTextSelection != null) mTextSelection.destroy(); NotificationHelper.destroy(); IntentHelper.destroy(); GeckoNetworkManager.destroy(); super.onDestroy(); - - if (!isFinishing()) { - // GeckoApp was not intentionally destroyed, so keep our process alive. - return; - } - - // Wait for Gecko to handle our pause event sent in onPause. - if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) { - GeckoThread.waitOnGecko(); - } - - if (mRestartIntent != null) { - // Restarting, so let Restarter kill us. - final Intent intent = new Intent(); - intent.setClass(getApplicationContext(), Restarter.class) - .putExtra("pid", Process.myPid()) - .putExtra(Intent.EXTRA_INTENT, mRestartIntent); - startService(intent); - } else { - // Exiting, so kill our own process. - Process.killProcess(Process.myPid()); - } } @Override protected void initializeChrome() { super.initializeChrome(); mDoorHangerPopup.setAnchor(mBrowserToolbar.getDoorHangerAnchor()); mDoorHangerPopup.setOnVisibilityChangeListener(this); @@ -1984,16 +1963,24 @@ public class BrowserApp extends GeckoApp .execute(IconsHelper.createBase64EventCallback(callback)); break; case "Feedback:MaybeLater": SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE); settings.edit().putInt(getPackageName() + ".feedback_launch_count", 0).apply(); break; + case "Sanitize:Finished": + if (message.getBoolean("shutdown", false)) { + // Gecko is shutting down and has called our sanitize handlers, + // so we can start exiting, too. + finishAndShutdown(/* restart */ false); + } + break; + case "Sanitize:OpenTabs": Tabs.getInstance().closeAll(); callback.sendSuccess(null); break; case "Sanitize:ClearHistory": BrowserDB.from(getProfile()).clearHistory( getContentResolver(), message.getBoolean("clearSearchHistory", false)); @@ -3791,17 +3778,17 @@ public class BrowserApp extends GeckoApp if (type == GuestModeDialog.ENTERING) { GeckoProfile.enterGuestMode(context); } else { GeckoProfile.leaveGuestMode(context); // Now's a good time to make sure we're not displaying the // Guest Browsing notification. GuestSession.hideNotification(context); } - doRestart(); + finishAndShutdown(/* restart */ true); } }); Resources res = getResources(); ps.setButtons(new String[] { res.getString(R.string.guest_session_dialog_continue), res.getString(R.string.guest_session_dialog_cancel) });
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -373,17 +373,18 @@ public abstract class GeckoApp private Telemetry.Timer mJavaUiStartupTimer; private Telemetry.Timer mGeckoReadyStartupTimer; private String mPrivateBrowsingSession; private volatile HealthRecorder mHealthRecorder; private volatile Locale mLastLocale; - protected Intent mRestartIntent; + private boolean mShutdownOnDestroy; + private boolean mRestartOnShutdown; private boolean mWasFirstTabShownAfterActivityUnhidden; abstract public int getLayout(); abstract public View getDoorhangerOverlay(); protected void processTabQueue() {}; @@ -667,17 +668,17 @@ public abstract class GeckoApp final String sessionRestore = getSessionRestorePreference(getSharedPreferences()); res.putBoolean("dontSaveSession", "quit".equals(sessionRestore)); } EventDispatcher.getInstance().dispatch("Browser:Quit", res); - // We don't call doShutdown() here because this creates a race condition which + // We don't call shutdown here because this creates a race condition which // can cause the clearing of private data to fail. Instead, we shut down the // UI only after we're done sanitizing. return true; } return super.onOptionsItemSelected(item); } @@ -751,27 +752,16 @@ public abstract class GeckoApp // Reset the crash loop counter if we remain alive for at least half a minute. ThreadUtils.postDelayedToBackgroundThread(new Runnable() { @Override public void run() { getSharedPreferences().edit().putInt(PREFS_CRASHED_COUNT, 0).apply(); } }, STARTUP_PHASE_DURATION_MS); - } else if ("Gecko:Exited".equals(event)) { - // Gecko thread exited first; let GeckoApp die too. - doShutdown(); - - } else if ("Sanitize:Finished".equals(event)) { - if (message.getBoolean("shutdown", false)) { - // Gecko is shutting down and has called our sanitize handlers, - // so we can start exiting, too. - doShutdown(); - } - } else if ("Accessibility:Ready".equals(event)) { GeckoAccessibility.updateAccessibilitySettings(this); } else if ("Accessibility:Event".equals(event)) { GeckoAccessibility.sendAccessibilityEvent(message); } else if ("Bookmark:Insert".equals(event)) { final BrowserDB db = BrowserDB.from(getProfile()); @@ -1306,17 +1296,17 @@ public abstract class GeckoApp // the UI. // This is using a sledgehammer to crack a nut, but it'll do for // now. // Our OS locale pref will be detected as invalid after the // restart, and will be propagated to Gecko accordingly, so there's // no need to touch that here. if (BrowserLocaleManager.getInstance().systemLocaleDidChange()) { Log.i(LOGTAG, "System locale changed. Restarting."); - doRestart(); + finishAndShutdown(/* restart */ true); return; } if (sAlreadyLoaded) { // This happens when the GeckoApp activity is destroyed by Android // without killing the entire application (see Bug 769269). // Now that we've got multiple GeckoApp-based activities, this can // also happen if we're not the first activity to run within a session. @@ -1347,23 +1337,21 @@ public abstract class GeckoApp // Start a speculative connection as soon as Gecko loads. GeckoThread.speculativeConnect(uri); } } // To prevent races, register startup events before launching the Gecko thread. EventDispatcher.getInstance().registerGeckoThreadListener(this, "Accessibility:Ready", - "Gecko:Exited", "Gecko:Ready", "PluginHelper:playFlash", null); EventDispatcher.getInstance().registerUiThreadListener(this, - "Sanitize:Finished", "Update:Check", "Update:Download", "Update:Install", null); GeckoThread.launch(); Bundle stateBundle = IntentUtils.getBundleExtraSafe(getIntent(), EXTRA_STATE_BUNDLE); @@ -2587,23 +2575,21 @@ public abstract class GeckoApp // This build does not support the Android version of the device: // We did not initialize anything, so skip cleaning up. super.onDestroy(); return; } EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Accessibility:Ready", - "Gecko:Exited", "Gecko:Ready", "PluginHelper:playFlash", null); EventDispatcher.getInstance().unregisterUiThreadListener(this, - "Sanitize:Finished", "Update:Check", "Update:Download", "Update:Install", null); getAppEventDispatcher().unregisterGeckoThreadListener(this, "Accessibility:Event", "Locale:Set", @@ -2644,16 +2630,21 @@ public abstract class GeckoApp rec.close(GeckoApp.this); } }); } super.onDestroy(); Tabs.unregisterOnTabsChangedListener(this); + + if (mShutdownOnDestroy) { + GeckoApplication.shutdown(!mRestartOnShutdown ? null : new Intent( + Intent.ACTION_MAIN, /* uri */ null, getApplicationContext(), getClass())); + } } public void showSDKVersionError() { final String message = getString(R.string.unsupported_sdk_version, HardwareUtils.getRealAbi(), Integer.toString(Build.VERSION.SDK_INT)); Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } @@ -2708,16 +2699,29 @@ public abstract class GeckoApp while (envIter.hasNext()) { Map.Entry<String, String> entry = envIter.next(); intent.putExtra("env" + c, entry.getKey() + "=" + entry.getValue()); c++; } } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + protected void finishAndShutdown(final boolean restart) { + ThreadUtils.assertOnUiThread(); + + mShutdownOnDestroy = true; + mRestartOnShutdown = restart; + + // Shut down the activity and then Gecko. + if (!isFinishing() && (Versions.preJBMR1 || !isDestroyed())) { + finish(); + } + } + @Override public void doRestart() { doRestart(null, null); } public void doRestart(String args) { doRestart(args, null); } @@ -3104,34 +3108,38 @@ public abstract class GeckoApp // trigger a session transition and subsequent events will be recorded in an environment // with the wrong locale. final HealthRecorder rec = mHealthRecorder; if (rec != null) { rec.onAppLocaleChanged(locale); rec.onEnvironmentChanged(startNewSession, SESSION_END_LOCALE_CHANGED); } - if (!shouldRestart) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - GeckoApp.this.onLocaleReady(locale); - } - }); - return; - } - - // Do this in the background so that the health recorder has its - // time to finish. - ThreadUtils.postToBackgroundThread(new Runnable() { + final Runnable runnable = new Runnable() { @Override public void run() { - GeckoApp.this.doRestart(); + if (!ThreadUtils.isOnUiThread()) { + ThreadUtils.postToUiThread(this); + return; + } + if (!shouldRestart) { + GeckoApp.this.onLocaleReady(locale); + } else { + finishAndShutdown(/* restart */ true); + } } - }); + }; + + if (!shouldRestart) { + ThreadUtils.postToUiThread(runnable); + } else { + // Do this in the background so that the health recorder has its + // time to finish. + ThreadUtils.postToBackgroundThread(runnable); + } } /** * Use BrowserLocaleManager to change our persisted and current locales, * and poke the system to tell it of our changed state. */ protected void setLocale(final String locale) { if (locale == null) {
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java @@ -2,18 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko; import android.app.Application; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.os.Process; import android.os.SystemClock; import android.util.Log; import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.RefWatcher; import org.mozilla.gecko.db.BrowserContract; import org.mozilla.gecko.db.BrowserDB; @@ -73,16 +75,39 @@ public class GeckoApplication extends Ap /** * @return The string representation of an UUID that changes on each application startup. */ public static String getSessionUUID() { return sSessionUUID; } + public static void shutdown(final Intent restartIntent) { + ThreadUtils.assertOnUiThread(); + + // Wait for Gecko to handle any pause events. + if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) { + GeckoThread.waitOnGecko(); + } + + if (restartIntent == null) { + // Exiting, so kill our own process. + Process.killProcess(Process.myPid()); + return; + } + + // Restarting, so let Restarter kill us. + final Context context = GeckoAppShell.getApplicationContext(); + final Intent intent = new Intent(); + intent.setClass(context, Restarter.class) + .putExtra("pid", Process.myPid()) + .putExtra(Intent.EXTRA_INTENT, restartIntent); + context.startService(intent); + } + @Override public Context getContext() { return this; } @Override public SharedPreferences getSharedPreferences() { return GeckoSharedPrefs.forApp(this); @@ -195,18 +220,23 @@ public class GeckoApplication extends Ap GeckoAppShell.setNotificationListener(new NotificationClient(context)); // This getInstance call will force initialization of the NotificationHelper, but does nothing with the result NotificationHelper.getInstance(context).init(); MulticastDNSManager.getInstance(context).init(); GeckoService.register(); - EventDispatcher.getInstance().registerBackgroundThreadListener(new EventListener(), - "Profile:Create"); + final EventListener listener = new EventListener(); + EventDispatcher.getInstance().registerUiThreadListener(listener, + "Gecko:Exited", + null); + EventDispatcher.getInstance().registerBackgroundThreadListener(listener, + "Profile:Create", + null); super.onCreate(); } public void onDelayedStartup() { if (AppConstants.MOZ_ANDROID_GCM) { // TODO: only run in main process. ThreadUtils.postToBackgroundThread(new Runnable() { @@ -315,16 +345,28 @@ public class GeckoApplication extends Ap } @Override // BundleEventListener public void handleMessage(final String event, final GeckoBundle message, final EventCallback callback) { if ("Profile:Create".equals(event)) { onProfileCreate(message.getString("name"), message.getString("path")); + + } else if ("Gecko:Exited".equals(event)) { + // Gecko thread exited first; shutdown the application. + final Intent restartIntent; + if (message.getBoolean("restart")) { + restartIntent = new Intent(Intent.ACTION_MAIN); + restartIntent.setClassName(GeckoAppShell.getApplicationContext(), + AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS); + } else { + restartIntent = null; + } + shutdown(restartIntent); } } } public boolean isApplicationInBackground() { return mInBackground; }
--- a/mobile/android/base/java/org/mozilla/gecko/Restarter.java +++ b/mobile/android/base/java/org/mozilla/gecko/Restarter.java @@ -25,18 +25,17 @@ public class Restarter extends Service { try { Thread.sleep(100); } catch (final InterruptedException e) { } final Intent restartIntent = (Intent)intent.getParcelableExtra(Intent.EXTRA_INTENT); restartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .putExtra("didRestart", true) - .setClassName(getApplicationContext(), - AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS); + .setPackage(getApplicationContext().getPackageName()); startActivity(restartIntent); Log.d(LOGTAG, "Launched " + restartIntent); } @Override public int onStartCommand(Intent intent, int flags, int startId) { doRestart(intent); stopSelf(startId);