Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | package org.mozilla.gecko.background.healthreport; |
michael@0 | 6 | |
michael@0 | 7 | import java.util.Iterator; |
michael@0 | 8 | |
michael@0 | 9 | import org.json.JSONObject; |
michael@0 | 10 | import org.mozilla.gecko.AppConstants; |
michael@0 | 11 | import org.mozilla.gecko.SysInfo; |
michael@0 | 12 | import org.mozilla.gecko.background.common.GlobalConstants; |
michael@0 | 13 | import org.mozilla.gecko.background.common.log.Logger; |
michael@0 | 14 | |
michael@0 | 15 | import android.content.ContentProvider; |
michael@0 | 16 | import android.content.ContentProviderClient; |
michael@0 | 17 | import android.content.ContentResolver; |
michael@0 | 18 | import android.content.Context; |
michael@0 | 19 | |
michael@0 | 20 | /** |
michael@0 | 21 | * Construct a HealthReport environment from the current running system. |
michael@0 | 22 | */ |
michael@0 | 23 | public class EnvironmentBuilder { |
michael@0 | 24 | private static final String LOG_TAG = "GeckoEnvBuilder"; |
michael@0 | 25 | |
michael@0 | 26 | public static ContentProviderClient getContentProviderClient(Context context) { |
michael@0 | 27 | ContentResolver cr = context.getContentResolver(); |
michael@0 | 28 | return cr.acquireContentProviderClient(HealthReportConstants.HEALTH_AUTHORITY); |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | /** |
michael@0 | 32 | * Fetch the storage object associated with the provided |
michael@0 | 33 | * {@link ContentProviderClient}. If no storage instance can be found -- |
michael@0 | 34 | * perhaps because the {@link ContentProvider} is running in a different |
michael@0 | 35 | * process -- returns <code>null</code>. On success, the returned |
michael@0 | 36 | * {@link HealthReportDatabaseStorage} instance is owned by the underlying |
michael@0 | 37 | * {@link HealthReportProvider} and thus does not need to be closed by the |
michael@0 | 38 | * caller. |
michael@0 | 39 | * |
michael@0 | 40 | * If the provider is not a {@link HealthReportProvider}, throws a |
michael@0 | 41 | * {@link ClassCastException}, because that would be disastrous. |
michael@0 | 42 | */ |
michael@0 | 43 | public static HealthReportDatabaseStorage getStorage(ContentProviderClient cpc, |
michael@0 | 44 | String profilePath) { |
michael@0 | 45 | ContentProvider pr = cpc.getLocalContentProvider(); |
michael@0 | 46 | if (pr == null) { |
michael@0 | 47 | Logger.error(LOG_TAG, "Unable to retrieve local content provider. Running in a different process?"); |
michael@0 | 48 | return null; |
michael@0 | 49 | } |
michael@0 | 50 | try { |
michael@0 | 51 | return ((HealthReportProvider) pr).getProfileStorage(profilePath); |
michael@0 | 52 | } catch (ClassCastException ex) { |
michael@0 | 53 | Logger.error(LOG_TAG, "ContentProvider not a HealthReportProvider!", ex); |
michael@0 | 54 | throw ex; |
michael@0 | 55 | } |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | public static interface ProfileInformationProvider { |
michael@0 | 59 | public boolean isBlocklistEnabled(); |
michael@0 | 60 | public boolean isTelemetryEnabled(); |
michael@0 | 61 | public boolean isAcceptLangUserSet(); |
michael@0 | 62 | public long getProfileCreationTime(); |
michael@0 | 63 | |
michael@0 | 64 | public String getDistributionString(); |
michael@0 | 65 | public String getOSLocale(); |
michael@0 | 66 | public String getAppLocale(); |
michael@0 | 67 | |
michael@0 | 68 | public JSONObject getAddonsJSON(); |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | protected static void populateEnvironment(Environment e, |
michael@0 | 72 | ProfileInformationProvider info) { |
michael@0 | 73 | e.cpuCount = SysInfo.getCPUCount(); |
michael@0 | 74 | e.memoryMB = SysInfo.getMemSize(); |
michael@0 | 75 | |
michael@0 | 76 | e.appName = AppConstants.MOZ_APP_NAME; |
michael@0 | 77 | e.appID = AppConstants.MOZ_APP_ID; |
michael@0 | 78 | e.appVersion = AppConstants.MOZ_APP_VERSION; |
michael@0 | 79 | e.appBuildID = AppConstants.MOZ_APP_BUILDID; |
michael@0 | 80 | e.updateChannel = AppConstants.MOZ_UPDATE_CHANNEL; |
michael@0 | 81 | e.vendor = AppConstants.MOZ_APP_VENDOR; |
michael@0 | 82 | e.platformVersion = AppConstants.MOZILLA_VERSION; |
michael@0 | 83 | e.platformBuildID = AppConstants.MOZ_APP_BUILDID; |
michael@0 | 84 | e.xpcomabi = AppConstants.TARGET_XPCOM_ABI; |
michael@0 | 85 | e.os = "Android"; |
michael@0 | 86 | e.architecture = SysInfo.getArchABI(); // Not just "arm". |
michael@0 | 87 | e.sysName = SysInfo.getName(); |
michael@0 | 88 | e.sysVersion = SysInfo.getReleaseVersion(); |
michael@0 | 89 | |
michael@0 | 90 | e.profileCreation = (int) (info.getProfileCreationTime() / GlobalConstants.MILLISECONDS_PER_DAY); |
michael@0 | 91 | |
michael@0 | 92 | // Corresponds to Gecko pref "extensions.blocklist.enabled". |
michael@0 | 93 | e.isBlocklistEnabled = (info.isBlocklistEnabled() ? 1 : 0); |
michael@0 | 94 | |
michael@0 | 95 | // Corresponds to Gecko pref "toolkit.telemetry.enabled". |
michael@0 | 96 | e.isTelemetryEnabled = (info.isTelemetryEnabled() ? 1 : 0); |
michael@0 | 97 | |
michael@0 | 98 | e.extensionCount = 0; |
michael@0 | 99 | e.pluginCount = 0; |
michael@0 | 100 | e.themeCount = 0; |
michael@0 | 101 | |
michael@0 | 102 | JSONObject addons = info.getAddonsJSON(); |
michael@0 | 103 | if (addons == null) { |
michael@0 | 104 | return; |
michael@0 | 105 | } |
michael@0 | 106 | |
michael@0 | 107 | @SuppressWarnings("unchecked") |
michael@0 | 108 | Iterator<String> it = addons.keys(); |
michael@0 | 109 | while (it.hasNext()) { |
michael@0 | 110 | String key = it.next(); |
michael@0 | 111 | try { |
michael@0 | 112 | JSONObject addon = addons.getJSONObject(key); |
michael@0 | 113 | String type = addon.optString("type"); |
michael@0 | 114 | Logger.pii(LOG_TAG, "Add-on " + key + " is a " + type); |
michael@0 | 115 | if ("extension".equals(type)) { |
michael@0 | 116 | ++e.extensionCount; |
michael@0 | 117 | } else if ("plugin".equals(type)) { |
michael@0 | 118 | ++e.pluginCount; |
michael@0 | 119 | } else if ("theme".equals(type)) { |
michael@0 | 120 | ++e.themeCount; |
michael@0 | 121 | } else if ("service".equals(type)) { |
michael@0 | 122 | // Later. |
michael@0 | 123 | } else { |
michael@0 | 124 | Logger.debug(LOG_TAG, "Unknown add-on type: " + type); |
michael@0 | 125 | } |
michael@0 | 126 | } catch (Exception ex) { |
michael@0 | 127 | Logger.warn(LOG_TAG, "Failed to process add-on " + key, ex); |
michael@0 | 128 | } |
michael@0 | 129 | } |
michael@0 | 130 | |
michael@0 | 131 | e.addons = addons; |
michael@0 | 132 | |
michael@0 | 133 | // v2 environment fields. |
michael@0 | 134 | e.distribution = info.getDistributionString(); |
michael@0 | 135 | e.osLocale = info.getOSLocale(); |
michael@0 | 136 | e.appLocale = info.getAppLocale(); |
michael@0 | 137 | e.acceptLangSet = info.isAcceptLangUserSet() ? 1 : 0; |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | /** |
michael@0 | 141 | * Returns an {@link Environment} not linked to a storage instance, but |
michael@0 | 142 | * populated with current field values. |
michael@0 | 143 | * |
michael@0 | 144 | * @param info a source of profile data |
michael@0 | 145 | * @return the new {@link Environment} |
michael@0 | 146 | */ |
michael@0 | 147 | public static Environment getCurrentEnvironment(ProfileInformationProvider info) { |
michael@0 | 148 | Environment e = new Environment() { |
michael@0 | 149 | @Override |
michael@0 | 150 | public int register() { |
michael@0 | 151 | return 0; |
michael@0 | 152 | } |
michael@0 | 153 | }; |
michael@0 | 154 | populateEnvironment(e, info); |
michael@0 | 155 | return e; |
michael@0 | 156 | } |
michael@0 | 157 | |
michael@0 | 158 | /** |
michael@0 | 159 | * @return the current environment's ID in the provided storage layer |
michael@0 | 160 | */ |
michael@0 | 161 | public static int registerCurrentEnvironment(final HealthReportStorage storage, |
michael@0 | 162 | final ProfileInformationProvider info) { |
michael@0 | 163 | Environment e = storage.getEnvironment(); |
michael@0 | 164 | populateEnvironment(e, info); |
michael@0 | 165 | e.register(); |
michael@0 | 166 | Logger.debug(LOG_TAG, "Registering current environment: " + e.getHash() + " = " + e.id); |
michael@0 | 167 | return e.id; |
michael@0 | 168 | } |
michael@0 | 169 | } |