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