This commit is contained in:
Richard Newman 2013-07-02 18:52:48 -07:00
Родитель 1b5b103f80 b4ec1c14bd
Коммит bf96eadef1
8 изменённых файлов: 130 добавлений и 39 удалений

Просмотреть файл

@ -128,7 +128,7 @@ def bootstrap(topsrcdir, mozilla_dir=None):
if not os.path.exists(state_env_dir):
print('Creating global state directory from environment variable: %s'
% state_env_dir)
os.makedirs(state_env_dir, mode=0777)
os.makedirs(state_env_dir, mode=0o770)
print('Please re-run mach.')
sys.exit(1)
else:

Просмотреть файл

@ -7844,7 +7844,15 @@ else
fi
if test "$MOZ_WIDGET_TOOLKIT" = "android"; then
dnl On Android, static resources live in the assets/ folder of the APK.
dnl Fennec's static resources live in the assets/ folder of the
dnl APK. Adding a path to the name here works because we only
dnl have one omnijar file in the final package (which is not the
dnl case on desktop), and necessitates some contortions during
dnl packaging so that the resources in the omnijar are considered
dnl as rooted at / and not as rooted at assets/ (which again is
dnl not the case on desktop: there are omnijars rooted at webrtc/,
dnl etc). packager.mk handles changing the rooting of the single
dnl omnijar.
OMNIJAR_NAME=assets/omni.ja
else
OMNIJAR_NAME=omni.ja

Просмотреть файл

@ -556,9 +556,13 @@ abstract public class GeckoApp
geckoConnected();
// This method is already running on the background thread, so we
// know that mHealthRecorder will exist. This method is cheap, so
// don't spawn a new runnable.
mHealthRecorder.recordGeckoStartupTime(mGeckoReadyStartupTimer.getElapsed());
// know that mHealthRecorder will exist. That doesn't stop us being
// paranoid.
// This method is cheap, so don't spawn a new runnable.
final BrowserHealthRecorder rec = mHealthRecorder;
if (rec != null) {
rec.recordGeckoStartupTime(mGeckoReadyStartupTimer.getElapsed());
}
} else if (event.equals("ToggleChrome:Hide")) {
toggleChrome(false);
} else if (event.equals("ToggleChrome:Show")) {
@ -1532,7 +1536,10 @@ abstract public class GeckoApp
ThreadUtils.getBackgroundHandler().postDelayed(new Runnable() {
@Override
public void run() {
mHealthRecorder.recordJavaStartupTime(javaDuration);
final BrowserHealthRecorder rec = mHealthRecorder;
if (rec != null) {
rec.recordJavaStartupTime(javaDuration);
}
// Sync settings need Gecko to be loaded, so
// no hurry in starting this.
@ -1879,7 +1886,6 @@ abstract public class GeckoApp
// track the duration of the session.
final long now = System.currentTimeMillis();
final long realTime = android.os.SystemClock.elapsedRealtime();
final BrowserHealthRecorder rec = mHealthRecorder;
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
@ -1894,8 +1900,11 @@ abstract public class GeckoApp
currentSession.recordBegin(editor);
editor.commit();
final BrowserHealthRecorder rec = mHealthRecorder;
if (rec != null) {
rec.setCurrentSession(currentSession);
} else {
Log.w(LOGTAG, "Can't record session: rec is null.");
}
}
});

Просмотреть файл

@ -427,7 +427,16 @@ public class HealthReportGenerator {
/**
* Compute the *tree* difference set between the two objects. If the two
* objects are identical, returns null.
* objects are identical, returns <code>null</code>. If <code>from</code> is
* <code>null</code>, returns <code>to</code>. If <code>to</code> is
* <code>null</code>, behaves as if <code>to</code> were an empty object.
*
* (Note that this method does not check for {@link JSONObject#NULL}, because
* by definition it can't be provided as input to this method.)
*
* This behavior is intended to simplify life for callers: a missing object
* can be viewed as (and behaves as) an empty map, to a useful extent, rather
* than throwing an exception.
*
* @param from
* a JSONObject.
@ -445,10 +454,14 @@ public class HealthReportGenerator {
public static JSONObject diff(JSONObject from,
JSONObject to,
boolean includeNull) throws JSONException {
if (from == null || from == JSONObject.NULL) {
if (from == null) {
return to;
}
if (to == null) {
return diff(from, new JSONObject(), includeNull);
}
JSONObject out = new JSONObject();
HashSet<String> toKeys = includeNull ? new HashSet<String>(to.length())

Просмотреть файл

@ -777,9 +777,17 @@ public class BrowserHealthRecorder implements GeckoEventListener {
final int day = storage.getDay();
final int env = this.env;
final String key = getEngineKey(engine);
final BrowserHealthRecorder self = this;
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final HealthReportDatabaseStorage storage = self.storage;
if (storage == null) {
Log.d(LOG_TAG, "No storage: not recording search. Shutting down?");
return;
}
Log.d(LOG_TAG, "Recording search: " + key + ", " + location +
" (" + day + ", " + env + ").");
final int searchField = storage.getField(MEASUREMENT_NAME_SEARCH_COUNTS,
@ -829,8 +837,12 @@ public class BrowserHealthRecorder implements GeckoEventListener {
*
* "r": reason. Values are "P" (activity paused), "A" (abnormal termination)
* "d": duration. Value in seconds.
* "sg": Gecko startup time. Present if this is a clean launch.
* "sj": Java startup time. Present if this is a clean launch.
* "sg": Gecko startup time. Present if this is a clean launch. This
* corresponds to the telemetry timer FENNEC_STARTUP_TIME_GECKOREADY.
* "sj": Java activity init time. Present if this is a clean launch. This
* corresponds to the telemetry timer FENNEC_STARTUP_TIME_JAVAUI,
* and includes initialization tasks beyond initial
* onWindowFocusChanged.
*
* Abnormal terminations will be missing a duration and will feature these keys:
*

Просмотреть файл

@ -14,6 +14,7 @@ import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.background.healthreport.EnvironmentBuilder;
import org.mozilla.gecko.background.healthreport.HealthReportConstants;
import org.mozilla.gecko.background.healthreport.HealthReportDatabaseStorage;
import org.mozilla.gecko.background.healthreport.HealthReportGenerator;
@ -34,16 +35,15 @@ import org.json.JSONObject;
public class BrowserHealthReporter implements GeckoEventListener {
private static final String LOGTAG = "GeckoHealthRep";
public static final long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
public static final long MILLISECONDS_PER_SIX_MONTHS = 180 * MILLISECONDS_PER_DAY;
public static final String EVENT_REQUEST = "HealthReport:Request";
public static final String EVENT_RESPONSE = "HealthReport:Response";
protected final Context context;
public BrowserHealthReporter() {
GeckoAppShell.registerEventListener(EVENT_REQUEST, this);
final Context context = GeckoAppShell.getContext();
context = GeckoAppShell.getContext();
if (context == null) {
throw new IllegalStateException("Null Gecko context");
}
@ -62,14 +62,11 @@ public class BrowserHealthReporter implements GeckoEventListener {
* @param lastPingTime timestamp when last health report was uploaded
* (milliseconds since epoch).
* @param profilePath path of the profile to generate report for.
* @throws JSONException if JSON generation fails.
* @throws IllegalStateException if the environment does not allow to generate a report.
* @return non-null report.
*/
public JSONObject generateReport(long since, long lastPingTime, String profilePath) throws JSONException {
final Context context = GeckoAppShell.getContext();
if (context == null) {
Log.e(LOGTAG, "Null Gecko context; returning null report.", new RuntimeException());
return null;
}
// We abuse the life-cycle of an Android ContentProvider slightly by holding
// onto a ContentProviderClient while we generate a payload. This keeps
// our database storage alive, while also allowing us to share a database
@ -86,29 +83,50 @@ public class BrowserHealthReporter implements GeckoEventListener {
// to close it.
HealthReportDatabaseStorage storage = EnvironmentBuilder.getStorage(client, profilePath);
if (storage == null) {
Log.e(LOGTAG, "No storage in health reporter; returning null report.", new RuntimeException());
return null;
throw new IllegalStateException("No storage in Health Reporter.");
}
HealthReportGenerator generator = new HealthReportGenerator(storage);
return generator.generateDocument(since, lastPingTime, profilePath);
JSONObject report = generator.generateDocument(since, lastPingTime, profilePath);
if (report == null) {
throw new IllegalStateException("Not enough profile information to generate report.");
}
return report;
} finally {
client.release();
}
}
/**
* Get last time a health report was successfully uploaded.
*
* This is read from shared preferences, so call it from a background
* thread. Bug 882182 tracks making this work with multiple profiles.
*
* @return milliseconds since the epoch, or 0 if never uploaded.
*/
protected long getLastUploadLocalTime() {
return context
.getSharedPreferences(HealthReportConstants.PREFS_BRANCH, 0)
.getLong(HealthReportConstants.PREF_LAST_UPLOAD_LOCAL_TIME, 0L);
}
/**
* Generate a new Health Report for the current Gecko profile.
*
* This method performs IO, so call it from a background thread.
*
* @throws JSONException if JSON generation fails.
* @throws IllegalStateException if the environment does not allow to generate a report.
* @return non-null Health Report.
*/
public JSONObject generateReport() throws JSONException {
GeckoProfile profile = GeckoAppShell.getGeckoInterface().getProfile();
String profilePath = profile.getDir().getAbsolutePath();
long since = System.currentTimeMillis() - MILLISECONDS_PER_SIX_MONTHS;
// TODO: read this from per-profile SharedPreference owned by background uploader.
long lastPingTime = since;
long since = System.currentTimeMillis() - HealthReportConstants.MILLISECONDS_PER_SIX_MONTHS;
long lastPingTime = Math.max(getLastUploadLocalTime(), HealthReportConstants.EARLIEST_LAST_PING);
return generateReport(since, lastPingTime, profilePath);
}
@ -118,11 +136,12 @@ public class BrowserHealthReporter implements GeckoEventListener {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
JSONObject report = new JSONObject();
JSONObject report = null;
try {
report = generateReport();
report = generateReport(); // non-null if it returns.
} catch (Exception e) {
Log.e(LOGTAG, "Generating report failed; responding with null.", e);
Log.e(LOGTAG, "Generating report failed; responding with empty report.", e);
report = new JSONObject();
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(EVENT_RESPONSE, report.toString()));

Просмотреть файл

@ -204,7 +204,6 @@ function FormTracker(name, engine) {
Tracker.call(this, name, engine);
Svc.Obs.add("weave:engine:start-tracking", this);
Svc.Obs.add("weave:engine:stop-tracking", this);
Svc.Obs.add("profile-change-teardown", this);
}
FormTracker.prototype = {
__proto__: Tracker.prototype,
@ -243,16 +242,17 @@ FormTracker.prototype = {
case "satchel-storage-changed":
if (data == "formhistory-add" || data == "formhistory-remove") {
let guid = subject.QueryInterface(Ci.nsISupportsString).toString();
this.addChangedID(guid);
this.score += SCORE_INCREMENT_MEDIUM;
this.trackEntry(guid);
}
break;
case "profile-change-teardown":
FormWrapper._finalize();
break;
}
},
trackEntry: function (guid) {
this.addChangedID(guid);
this.score += SCORE_INCREMENT_MEDIUM;
},
notify: function (formElement, aWindow, actionURI) {
if (this.ignoreAll) {
return;
@ -320,7 +320,10 @@ FormTracker.prototype = {
// Get the GUID on a delay so that it can be added to the DB first...
Utils.nextTick(function() {
this._log.trace("Logging form element: " + [name, el.value]);
this.trackEntry(name, el.value);
let guid = FormWrapper.getGUID(name, el.value);
if (guid) {
this.trackEntry(guid);
}
}, this);
}
}

Просмотреть файл

@ -357,6 +357,19 @@ ifdef MOZ_ENABLE_SZIP
SZIP_LIBRARIES := $(ASSET_SO_LIBRARIES)
endif
# Fennec's OMNIJAR_NAME can include a directory; for example, it might
# be "assets/omni.ja". This path specifies where the omni.ja file
# lives in the APK, but should not root the resources it contains
# under assets/ (i.e., resources should not live at chrome://assets/).
# packager.py writes /omni.ja in order to be consistent with the
# layout expected by language repacks. Therefore, we move it to the
# correct path here, in INNER_MAKE_PACKAGE. See comment about
# OMNIJAR_NAME in configure.in.
# OMNIJAR_DIR is './' for "omni.ja", 'assets/' for "assets/omni.ja".
OMNIJAR_DIR := $(dir $(OMNIJAR_NAME))
OMNIJAR_NAME := $(notdir $(OMNIJAR_NAME))
PKG_SUFFIX = .apk
INNER_MAKE_PACKAGE = \
$(if $(ALREADY_SZIPPED),,$(foreach lib,$(SZIP_LIBRARIES),host/bin/szip $(MOZ_SZIP_FLAGS) $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/$(lib) && )) \
@ -369,7 +382,9 @@ INNER_MAKE_PACKAGE = \
rm $(_ABS_DIST)/gecko.ap_ && \
$(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(ASSET_SO_LIBRARIES) && \
$(ZIP) -r9D $(_ABS_DIST)/gecko.ap_ $(DIST_FILES) -x $(NON_DIST_FILES) $(SZIP_LIBRARIES) && \
$(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(OMNIJAR_NAME)) && \
$(if $(filter-out ./,$(OMNIJAR_DIR)), \
mkdir -p $(OMNIJAR_DIR) && mv $(OMNIJAR_NAME) $(OMNIJAR_DIR) && ) \
$(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(OMNIJAR_DIR)$(OMNIJAR_NAME)) && \
rm -f $(_ABS_DIST)/gecko.apk && \
cp $(_ABS_DIST)/gecko.ap_ $(_ABS_DIST)/gecko.apk && \
$(ZIP) -j0 $(_ABS_DIST)/gecko.apk $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
@ -378,13 +393,21 @@ INNER_MAKE_PACKAGE = \
$(ZIPALIGN) -f -v 4 $(_ABS_DIST)/gecko.apk $(PACKAGE) && \
$(INNER_ROBOCOP_PACKAGE)
# Language repacks root the resources contained in assets/omni.ja
# under assets/, but the repacks expect them to be rooted at /.
# Therefore, we we move the omnijar back to / so the resources are
# under the root here, in INNER_UNMAKE_PACKAGE. See comments about
# OMNIJAR_NAME earlier in this file and in configure.in.
INNER_UNMAKE_PACKAGE = \
mkdir $(MOZ_PKG_DIR) && \
( cd $(MOZ_PKG_DIR) && \
$(UNZIP) $(UNPACKAGE) && \
mv lib/$(ABI_DIR)/libmozglue.so . && \
mv lib/$(ABI_DIR)/*plugin-container* $(MOZ_CHILD_PROCESS_NAME) && \
rm -rf lib/$(ABI_DIR) )
rm -rf lib/$(ABI_DIR) \
$(if $(filter-out ./,$(OMNIJAR_DIR)), \
&& mv $(OMNIJAR_DIR)$(OMNIJAR_NAME) $(OMNIJAR_NAME)) )
endif
ifeq ($(MOZ_PKG_FORMAT),DMG)
@ -584,8 +607,12 @@ endif
export NO_PKG_FILES USE_ELF_HACK ELF_HACK_FLAGS
# Override the value of OMNIJAR_NAME from config.status with the value
# set earlier in this file.
stage-package: $(MOZ_PKG_MANIFEST)
@rm -rf $(DIST)/$(PKG_PATH)$(PKG_BASENAME).tar $(DIST)/$(PKG_PATH)$(PKG_BASENAME).dmg $@ $(EXCLUDE_LIST)
OMNIJAR_NAME=$(OMNIJAR_NAME) \
$(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/packager.py $(DEFINES) \
--format $(MOZ_PACKAGER_FORMAT) \
$(addprefix --removals ,$(MOZ_PKG_REMOVALS)) \