GfxInfoBase.cpp 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. *
  3. * This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. #include "mozilla/ArrayUtils.h"
  7. #include "GfxInfoBase.h"
  8. #include "GfxInfoWebGL.h"
  9. #include "GfxDriverInfo.h"
  10. #include "nsCOMPtr.h"
  11. #include "nsCOMArray.h"
  12. #include "nsString.h"
  13. #include "nsUnicharUtils.h"
  14. #include "nsVersionComparator.h"
  15. #include "mozilla/Services.h"
  16. #include "mozilla/Observer.h"
  17. #include "nsIObserver.h"
  18. #include "nsIObserverService.h"
  19. #include "nsIDOMElement.h"
  20. #include "nsIDOMHTMLCollection.h"
  21. #include "nsIDOMNode.h"
  22. #include "nsIDOMNodeList.h"
  23. #include "nsTArray.h"
  24. #include "nsXULAppAPI.h"
  25. #include "nsIXULAppInfo.h"
  26. #include "mozilla/Preferences.h"
  27. #include "mozilla/dom/ContentChild.h"
  28. #include "mozilla/gfx/2D.h"
  29. #include "mozilla/gfx/Logging.h"
  30. #include "MediaPrefs.h"
  31. #include "gfxPrefs.h"
  32. #include "gfxPlatform.h"
  33. #include "gfxConfig.h"
  34. #include "DriverCrashGuard.h"
  35. using namespace mozilla::widget;
  36. using namespace mozilla;
  37. using mozilla::MutexAutoLock;
  38. nsTArray<GfxDriverInfo>* GfxInfoBase::mDriverInfo;
  39. bool GfxInfoBase::mDriverInfoObserverInitialized;
  40. bool GfxInfoBase::mShutdownOccurred;
  41. // Observes for shutdown so that the child GfxDriverInfo list is freed.
  42. class ShutdownObserver : public nsIObserver
  43. {
  44. virtual ~ShutdownObserver() {}
  45. public:
  46. ShutdownObserver() {}
  47. NS_DECL_ISUPPORTS
  48. NS_IMETHOD Observe(nsISupports *subject, const char *aTopic,
  49. const char16_t *aData) override
  50. {
  51. MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
  52. delete GfxInfoBase::mDriverInfo;
  53. GfxInfoBase::mDriverInfo = nullptr;
  54. for (uint32_t i = 0; i < DeviceFamilyMax; i++) {
  55. delete GfxDriverInfo::mDeviceFamilies[i];
  56. GfxDriverInfo::mDeviceFamilies[i] = nullptr;
  57. }
  58. for (uint32_t i = 0; i < DeviceVendorMax; i++) {
  59. delete GfxDriverInfo::mDeviceVendors[i];
  60. GfxDriverInfo::mDeviceVendors[i] = nullptr;
  61. }
  62. GfxInfoBase::mShutdownOccurred = true;
  63. return NS_OK;
  64. }
  65. };
  66. NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver)
  67. void InitGfxDriverInfoShutdownObserver()
  68. {
  69. if (GfxInfoBase::mDriverInfoObserverInitialized)
  70. return;
  71. GfxInfoBase::mDriverInfoObserverInitialized = true;
  72. nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
  73. if (!observerService) {
  74. NS_WARNING("Could not get observer service!");
  75. return;
  76. }
  77. ShutdownObserver *obs = new ShutdownObserver();
  78. observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
  79. }
  80. using namespace mozilla::widget;
  81. using namespace mozilla::gfx;
  82. using namespace mozilla;
  83. NS_IMPL_ISUPPORTS(GfxInfoBase, nsIGfxInfo, nsIObserver, nsISupportsWeakReference)
  84. #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
  85. #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
  86. #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
  87. static const char*
  88. GetPrefNameForFeature(int32_t aFeature)
  89. {
  90. const char* name = nullptr;
  91. switch(aFeature) {
  92. case nsIGfxInfo::FEATURE_DIRECT2D:
  93. name = BLACKLIST_PREF_BRANCH "direct2d";
  94. break;
  95. case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS:
  96. name = BLACKLIST_PREF_BRANCH "layers.direct3d9";
  97. break;
  98. case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS:
  99. name = BLACKLIST_PREF_BRANCH "layers.direct3d10";
  100. break;
  101. case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS:
  102. name = BLACKLIST_PREF_BRANCH "layers.direct3d10-1";
  103. break;
  104. case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS:
  105. name = BLACKLIST_PREF_BRANCH "layers.direct3d11";
  106. break;
  107. case nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE:
  108. name = BLACKLIST_PREF_BRANCH "direct3d11angle";
  109. break;
  110. case nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING:
  111. name = BLACKLIST_PREF_BRANCH "hardwarevideodecoding";
  112. break;
  113. case nsIGfxInfo::FEATURE_OPENGL_LAYERS:
  114. name = BLACKLIST_PREF_BRANCH "layers.opengl";
  115. break;
  116. case nsIGfxInfo::FEATURE_WEBGL_OPENGL:
  117. name = BLACKLIST_PREF_BRANCH "webgl.opengl";
  118. break;
  119. case nsIGfxInfo::FEATURE_WEBGL_ANGLE:
  120. name = BLACKLIST_PREF_BRANCH "webgl.angle";
  121. break;
  122. case nsIGfxInfo::FEATURE_WEBGL_MSAA:
  123. name = BLACKLIST_PREF_BRANCH "webgl.msaa";
  124. break;
  125. case nsIGfxInfo::FEATURE_STAGEFRIGHT:
  126. name = BLACKLIST_PREF_BRANCH "stagefright";
  127. break;
  128. case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION:
  129. name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration";
  130. break;
  131. case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE:
  132. name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration.encode";
  133. break;
  134. case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE:
  135. name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration.decode";
  136. break;
  137. case nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION:
  138. name = BLACKLIST_PREF_BRANCH "canvas2d.acceleration";
  139. break;
  140. case nsIGfxInfo::FEATURE_VP8_HW_DECODE:
  141. case nsIGfxInfo::FEATURE_VP9_HW_DECODE:
  142. case nsIGfxInfo::FEATURE_DX_INTEROP2:
  143. // We don't provide prefs for these features.
  144. break;
  145. default:
  146. MOZ_ASSERT_UNREACHABLE("Unexpected nsIGfxInfo feature?!");
  147. break;
  148. }
  149. return name;
  150. }
  151. // Returns the value of the pref for the relevant feature in aValue.
  152. // If the pref doesn't exist, aValue is not touched, and returns false.
  153. static bool
  154. GetPrefValueForFeature(int32_t aFeature, int32_t& aValue, nsACString& aFailureId)
  155. {
  156. const char *prefname = GetPrefNameForFeature(aFeature);
  157. if (!prefname)
  158. return false;
  159. aValue = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
  160. if (!NS_SUCCEEDED(Preferences::GetInt(prefname, &aValue))) {
  161. return false;
  162. }
  163. nsCString failureprefname(prefname);
  164. failureprefname += ".failureid";
  165. nsAdoptingCString failureValue = Preferences::GetCString(failureprefname.get());
  166. if (failureValue) {
  167. aFailureId = failureValue.get();
  168. } else {
  169. aFailureId = "FEATURE_FAILURE_BLACKLIST_PREF";
  170. }
  171. return true;
  172. }
  173. static void
  174. SetPrefValueForFeature(int32_t aFeature, int32_t aValue, const nsACString& aFailureId)
  175. {
  176. const char *prefname = GetPrefNameForFeature(aFeature);
  177. if (!prefname)
  178. return;
  179. Preferences::SetInt(prefname, aValue);
  180. if (!aFailureId.IsEmpty()) {
  181. nsCString failureprefname(prefname);
  182. failureprefname += ".failureid";
  183. Preferences::SetCString(failureprefname.get(), aFailureId);
  184. }
  185. }
  186. static void
  187. RemovePrefForFeature(int32_t aFeature)
  188. {
  189. const char *prefname = GetPrefNameForFeature(aFeature);
  190. if (!prefname)
  191. return;
  192. Preferences::ClearUser(prefname);
  193. }
  194. static bool
  195. GetPrefValueForDriverVersion(nsCString& aVersion)
  196. {
  197. return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF,
  198. &aVersion));
  199. }
  200. static void
  201. SetPrefValueForDriverVersion(const nsAString& aVersion)
  202. {
  203. Preferences::SetString(SUGGESTED_VERSION_PREF, aVersion);
  204. }
  205. static void
  206. RemovePrefForDriverVersion()
  207. {
  208. Preferences::ClearUser(SUGGESTED_VERSION_PREF);
  209. }
  210. static OperatingSystem
  211. BlacklistOSToOperatingSystem(const nsAString& os)
  212. {
  213. if (os.EqualsLiteral("WINNT 6.1"))
  214. return OperatingSystem::Windows7;
  215. else if (os.EqualsLiteral("WINNT 6.2"))
  216. return OperatingSystem::Windows8;
  217. else if (os.EqualsLiteral("WINNT 6.3"))
  218. return OperatingSystem::Windows8_1;
  219. else if (os.EqualsLiteral("WINNT 10.0"))
  220. return OperatingSystem::Windows10;
  221. else if (os.EqualsLiteral("Linux"))
  222. return OperatingSystem::Linux;
  223. // For historical reasons, "All" in blocklist means "All Windows"
  224. else if (os.EqualsLiteral("All"))
  225. return OperatingSystem::Windows;
  226. return OperatingSystem::Unknown;
  227. }
  228. static GfxDeviceFamily*
  229. BlacklistDevicesToDeviceFamily(nsTArray<nsCString>& devices)
  230. {
  231. if (devices.Length() == 0)
  232. return nullptr;
  233. // For each device, get its device ID, and return a freshly-allocated
  234. // GfxDeviceFamily with the contents of that array.
  235. GfxDeviceFamily* deviceIds = new GfxDeviceFamily;
  236. for (uint32_t i = 0; i < devices.Length(); ++i) {
  237. // We make sure we don't add any "empty" device entries to the array, so
  238. // we don't need to check if devices[i] is empty.
  239. deviceIds->AppendElement(NS_ConvertUTF8toUTF16(devices[i]));
  240. }
  241. return deviceIds;
  242. }
  243. static int32_t
  244. BlacklistFeatureToGfxFeature(const nsAString& aFeature)
  245. {
  246. MOZ_ASSERT(!aFeature.IsEmpty());
  247. if (aFeature.EqualsLiteral("DIRECT2D"))
  248. return nsIGfxInfo::FEATURE_DIRECT2D;
  249. else if (aFeature.EqualsLiteral("DIRECT3D_9_LAYERS"))
  250. return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS;
  251. else if (aFeature.EqualsLiteral("DIRECT3D_10_LAYERS"))
  252. return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS;
  253. else if (aFeature.EqualsLiteral("DIRECT3D_10_1_LAYERS"))
  254. return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS;
  255. else if (aFeature.EqualsLiteral("DIRECT3D_11_LAYERS"))
  256. return nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS;
  257. else if (aFeature.EqualsLiteral("DIRECT3D_11_ANGLE"))
  258. return nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE;
  259. else if (aFeature.EqualsLiteral("HARDWARE_VIDEO_DECODING"))
  260. return nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING;
  261. else if (aFeature.EqualsLiteral("OPENGL_LAYERS"))
  262. return nsIGfxInfo::FEATURE_OPENGL_LAYERS;
  263. else if (aFeature.EqualsLiteral("WEBGL_OPENGL"))
  264. return nsIGfxInfo::FEATURE_WEBGL_OPENGL;
  265. else if (aFeature.EqualsLiteral("WEBGL_ANGLE"))
  266. return nsIGfxInfo::FEATURE_WEBGL_ANGLE;
  267. else if (aFeature.EqualsLiteral("WEBGL_MSAA"))
  268. return nsIGfxInfo::FEATURE_WEBGL_MSAA;
  269. else if (aFeature.EqualsLiteral("STAGEFRIGHT"))
  270. return nsIGfxInfo::FEATURE_STAGEFRIGHT;
  271. else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION_ENCODE"))
  272. return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE;
  273. else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION_DECODE"))
  274. return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE;
  275. else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION"))
  276. return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION;
  277. else if (aFeature.EqualsLiteral("CANVAS2D_ACCELERATION"))
  278. return nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION;
  279. // If we don't recognize the feature, it may be new, and something
  280. // this version doesn't understand. So, nothing to do. This is
  281. // different from feature not being specified at all, in which case
  282. // this method should not get called and we should continue with the
  283. // "all features" blocklisting.
  284. return -1;
  285. }
  286. static int32_t
  287. BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus)
  288. {
  289. if (aStatus.EqualsLiteral("STATUS_OK"))
  290. return nsIGfxInfo::FEATURE_STATUS_OK;
  291. else if (aStatus.EqualsLiteral("BLOCKED_DRIVER_VERSION"))
  292. return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
  293. else if (aStatus.EqualsLiteral("BLOCKED_DEVICE"))
  294. return nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
  295. else if (aStatus.EqualsLiteral("DISCOURAGED"))
  296. return nsIGfxInfo::FEATURE_DISCOURAGED;
  297. else if (aStatus.EqualsLiteral("BLOCKED_OS_VERSION"))
  298. return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
  299. // Do not allow it to set STATUS_UNKNOWN. Also, we are not
  300. // expecting the "mismatch" status showing up here.
  301. return nsIGfxInfo::FEATURE_STATUS_OK;
  302. }
  303. static VersionComparisonOp
  304. BlacklistComparatorToComparisonOp(const nsAString& op)
  305. {
  306. if (op.EqualsLiteral("LESS_THAN"))
  307. return DRIVER_LESS_THAN;
  308. else if (op.EqualsLiteral("BUILD_ID_LESS_THAN"))
  309. return DRIVER_BUILD_ID_LESS_THAN;
  310. else if (op.EqualsLiteral("LESS_THAN_OR_EQUAL"))
  311. return DRIVER_LESS_THAN_OR_EQUAL;
  312. else if (op.EqualsLiteral("BUILD_ID_LESS_THAN_OR_EQUAL"))
  313. return DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL;
  314. else if (op.EqualsLiteral("GREATER_THAN"))
  315. return DRIVER_GREATER_THAN;
  316. else if (op.EqualsLiteral("GREATER_THAN_OR_EQUAL"))
  317. return DRIVER_GREATER_THAN_OR_EQUAL;
  318. else if (op.EqualsLiteral("EQUAL"))
  319. return DRIVER_EQUAL;
  320. else if (op.EqualsLiteral("NOT_EQUAL"))
  321. return DRIVER_NOT_EQUAL;
  322. else if (op.EqualsLiteral("BETWEEN_EXCLUSIVE"))
  323. return DRIVER_BETWEEN_EXCLUSIVE;
  324. else if (op.EqualsLiteral("BETWEEN_INCLUSIVE"))
  325. return DRIVER_BETWEEN_INCLUSIVE;
  326. else if (op.EqualsLiteral("BETWEEN_INCLUSIVE_START"))
  327. return DRIVER_BETWEEN_INCLUSIVE_START;
  328. return DRIVER_COMPARISON_IGNORED;
  329. }
  330. /*
  331. Deserialize Blacklist entries from string.
  332. e.g:
  333. os:WINNT 6.0\tvendor:0x8086\tdevices:0x2582,0x2782\tfeature:DIRECT3D_10_LAYERS\tfeatureStatus:BLOCKED_DRIVER_VERSION\tdriverVersion:8.52.322.2202\tdriverVersionComparator:LESS_THAN_OR_EQUAL
  334. */
  335. static bool
  336. BlacklistEntryToDriverInfo(nsCString& aBlacklistEntry,
  337. GfxDriverInfo& aDriverInfo)
  338. {
  339. // If we get an application version to be zero, something is not working
  340. // and we are not going to bother checking the blocklist versions.
  341. // See TestGfxWidgets.cpp for how version comparison works.
  342. // <versionRange minVersion="42.0a1" maxVersion="45.0"></versionRange>
  343. static mozilla::Version zeroV("0");
  344. static mozilla::Version appV(GfxInfoBase::GetApplicationVersion().get());
  345. if (appV <= zeroV) {
  346. gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Invalid application version " << GfxInfoBase::GetApplicationVersion().get();
  347. }
  348. nsTArray<nsCString> keyValues;
  349. ParseString(aBlacklistEntry, '\t', keyValues);
  350. aDriverInfo.mRuleId = NS_LITERAL_CSTRING("FEATURE_FAILURE_DL_BLACKLIST_NO_ID");
  351. for (uint32_t i = 0; i < keyValues.Length(); ++i) {
  352. nsCString keyValue = keyValues[i];
  353. nsTArray<nsCString> splitted;
  354. ParseString(keyValue, ':', splitted);
  355. if (splitted.Length() != 2) {
  356. // If we don't recognize the input data, we do not want to proceed.
  357. gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized data " << keyValue.get();
  358. return false;
  359. }
  360. nsCString key = splitted[0];
  361. nsCString value = splitted[1];
  362. NS_ConvertUTF8toUTF16 dataValue(value);
  363. if (value.Length() == 0) {
  364. // Safety check for empty values.
  365. gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Empty value for " << key.get();
  366. return false;
  367. }
  368. if (key.EqualsLiteral("blockID")) {
  369. nsCString blockIdStr = NS_LITERAL_CSTRING("FEATURE_FAILURE_DL_BLACKLIST_") + value;
  370. aDriverInfo.mRuleId = blockIdStr.get();
  371. } else if (key.EqualsLiteral("os")) {
  372. aDriverInfo.mOperatingSystem = BlacklistOSToOperatingSystem(dataValue);
  373. } else if (key.EqualsLiteral("osversion")) {
  374. aDriverInfo.mOperatingSystemVersion = strtoul(value.get(), nullptr, 10);
  375. } else if (key.EqualsLiteral("vendor")) {
  376. aDriverInfo.mAdapterVendor = dataValue;
  377. } else if (key.EqualsLiteral("feature")) {
  378. aDriverInfo.mFeature = BlacklistFeatureToGfxFeature(dataValue);
  379. if (aDriverInfo.mFeature < 0) {
  380. // If we don't recognize the feature, we do not want to proceed.
  381. gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized feature " << value.get();
  382. return false;
  383. }
  384. } else if (key.EqualsLiteral("featureStatus")) {
  385. aDriverInfo.mFeatureStatus = BlacklistFeatureStatusToGfxFeatureStatus(dataValue);
  386. } else if (key.EqualsLiteral("driverVersion")) {
  387. uint64_t version;
  388. if (ParseDriverVersion(dataValue, &version))
  389. aDriverInfo.mDriverVersion = version;
  390. } else if (key.EqualsLiteral("driverVersionMax")) {
  391. uint64_t version;
  392. if (ParseDriverVersion(dataValue, &version))
  393. aDriverInfo.mDriverVersionMax = version;
  394. } else if (key.EqualsLiteral("driverVersionComparator")) {
  395. aDriverInfo.mComparisonOp = BlacklistComparatorToComparisonOp(dataValue);
  396. } else if (key.EqualsLiteral("model")) {
  397. aDriverInfo.mModel = dataValue;
  398. } else if (key.EqualsLiteral("product")) {
  399. aDriverInfo.mProduct = dataValue;
  400. } else if (key.EqualsLiteral("manufacturer")) {
  401. aDriverInfo.mManufacturer = dataValue;
  402. } else if (key.EqualsLiteral("hardware")) {
  403. aDriverInfo.mHardware = dataValue;
  404. } else if (key.EqualsLiteral("versionRange")) {
  405. nsTArray<nsCString> versionRange;
  406. ParseString(value, ',', versionRange);
  407. if (versionRange.Length() != 2) {
  408. gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized versionRange " << value.get();
  409. return false;
  410. }
  411. nsCString minValue = versionRange[0];
  412. nsCString maxValue = versionRange[1];
  413. mozilla::Version minV(minValue.get());
  414. mozilla::Version maxV(maxValue.get());
  415. if (minV > zeroV && !(appV >= minV)) {
  416. // The version of the application is less than the minimal version
  417. // this blocklist entry applies to, so we can just ignore it by
  418. // returning false and letting the caller deal with it.
  419. return false;
  420. }
  421. if (maxV > zeroV && !(appV <= maxV)) {
  422. // The version of the application is more than the maximal version
  423. // this blocklist entry applies to, so we can just ignore it by
  424. // returning false and letting the caller deal with it.
  425. return false;
  426. }
  427. } else if (key.EqualsLiteral("devices")) {
  428. nsTArray<nsCString> devices;
  429. ParseString(value, ',', devices);
  430. GfxDeviceFamily* deviceIds = BlacklistDevicesToDeviceFamily(devices);
  431. if (deviceIds) {
  432. // Get GfxDriverInfo to adopt the devices array we created.
  433. aDriverInfo.mDeleteDevices = true;
  434. aDriverInfo.mDevices = deviceIds;
  435. }
  436. }
  437. // We explicitly ignore unknown elements.
  438. }
  439. return true;
  440. }
  441. static void
  442. BlacklistEntriesToDriverInfo(nsTArray<nsCString>& aBlacklistEntries,
  443. nsTArray<GfxDriverInfo>& aDriverInfo)
  444. {
  445. aDriverInfo.Clear();
  446. aDriverInfo.SetLength(aBlacklistEntries.Length());
  447. for (uint32_t i = 0; i < aBlacklistEntries.Length(); ++i) {
  448. nsCString blacklistEntry = aBlacklistEntries[i];
  449. GfxDriverInfo di;
  450. if (BlacklistEntryToDriverInfo(blacklistEntry, di)) {
  451. aDriverInfo[i] = di;
  452. // Prevent di falling out of scope from destroying the devices.
  453. di.mDeleteDevices = false;
  454. }
  455. }
  456. }
  457. NS_IMETHODIMP
  458. GfxInfoBase::Observe(nsISupports* aSubject, const char* aTopic,
  459. const char16_t* aData)
  460. {
  461. if (strcmp(aTopic, "blocklist-data-gfxItems") == 0) {
  462. nsTArray<GfxDriverInfo> driverInfo;
  463. nsTArray<nsCString> blacklistEntries;
  464. nsCString utf8Data = NS_ConvertUTF16toUTF8(aData);
  465. if (utf8Data.Length() > 0) {
  466. ParseString(utf8Data, '\n', blacklistEntries);
  467. }
  468. BlacklistEntriesToDriverInfo(blacklistEntries, driverInfo);
  469. EvaluateDownloadedBlacklist(driverInfo);
  470. }
  471. return NS_OK;
  472. }
  473. GfxInfoBase::GfxInfoBase()
  474. : mMutex("GfxInfoBase")
  475. {
  476. }
  477. GfxInfoBase::~GfxInfoBase()
  478. {
  479. }
  480. nsresult
  481. GfxInfoBase::Init()
  482. {
  483. InitGfxDriverInfoShutdownObserver();
  484. gfxPrefs::GetSingleton();
  485. MediaPrefs::GetSingleton();
  486. nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  487. if (os) {
  488. os->AddObserver(this, "blocklist-data-gfxItems", true);
  489. }
  490. return NS_OK;
  491. }
  492. NS_IMETHODIMP
  493. GfxInfoBase::GetFeatureStatus(int32_t aFeature, nsACString& aFailureId, int32_t* aStatus)
  494. {
  495. int32_t blocklistAll = gfxPrefs::BlocklistAll();
  496. if (blocklistAll > 0) {
  497. gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Forcing blocklisting all features";
  498. *aStatus = FEATURE_BLOCKED_DEVICE;
  499. aFailureId = "FEATURE_FAILURE_BLOCK_ALL";
  500. return NS_OK;
  501. } else if (blocklistAll < 0) {
  502. gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Ignoring any feature blocklisting.";
  503. *aStatus = FEATURE_STATUS_OK;
  504. return NS_OK;
  505. }
  506. if (GetPrefValueForFeature(aFeature, *aStatus, aFailureId)) {
  507. return NS_OK;
  508. }
  509. if (XRE_IsContentProcess()) {
  510. // Delegate to the parent process.
  511. mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
  512. bool success;
  513. nsCString remoteFailureId;
  514. cc->SendGetGraphicsFeatureStatus(aFeature, aStatus, &remoteFailureId, &success);
  515. aFailureId = remoteFailureId;
  516. return success ? NS_OK : NS_ERROR_FAILURE;
  517. }
  518. nsString version;
  519. nsTArray<GfxDriverInfo> driverInfo;
  520. nsresult rv = GetFeatureStatusImpl(aFeature, aStatus, version, driverInfo, aFailureId);
  521. return rv;
  522. }
  523. // Matching OS go somewhat beyond the simple equality check because of the
  524. // "All Windows" and "All OS X" variations.
  525. //
  526. // aBlockedOS is describing the system(s) we are trying to block.
  527. // aSystemOS is describing the system we are running on.
  528. //
  529. // aSystemOS should not be "Windows" or "OSX" - it should be set to
  530. // a particular version instead.
  531. // However, it is valid for aBlockedOS to be one of those generic values,
  532. // as we could be blocking all of the versions.
  533. inline bool
  534. MatchingOperatingSystems(OperatingSystem aBlockedOS, OperatingSystem aSystemOS)
  535. {
  536. MOZ_ASSERT(aSystemOS != OperatingSystem::Windows &&
  537. aSystemOS != OperatingSystem::OSX);
  538. // If the block entry OS is unknown, it doesn't match
  539. if (aBlockedOS == OperatingSystem::Unknown) {
  540. return false;
  541. }
  542. #if defined (XP_WIN)
  543. if (aBlockedOS == OperatingSystem::Windows) {
  544. // We do want even "unknown" aSystemOS to fall under "all windows"
  545. return true;
  546. }
  547. #endif
  548. return aSystemOS == aBlockedOS;
  549. }
  550. int32_t
  551. GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info,
  552. nsAString& aSuggestedVersion,
  553. int32_t aFeature,
  554. nsACString& aFailureId,
  555. OperatingSystem os)
  556. {
  557. int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
  558. uint32_t i = 0;
  559. for (; i < info.Length(); i++) {
  560. // Do the operating system check first, no point in getting the driver
  561. // info if we won't need to use it.
  562. if (!MatchingOperatingSystems(info[i].mOperatingSystem, os)) {
  563. continue;
  564. }
  565. if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
  566. continue;
  567. }
  568. // XXX: it would be better not to do this everytime round the loop
  569. nsAutoString adapterVendorID;
  570. nsAutoString adapterDeviceID;
  571. nsAutoString adapterDriverVersionString;
  572. if (info[i].mGpu2) {
  573. if (NS_FAILED(GetAdapterVendorID2(adapterVendorID)) ||
  574. NS_FAILED(GetAdapterDeviceID2(adapterDeviceID)) ||
  575. NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString)))
  576. {
  577. return 0;
  578. }
  579. } else {
  580. if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
  581. NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
  582. NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
  583. {
  584. return 0;
  585. }
  586. }
  587. #ifdef XP_WIN
  588. uint64_t driverVersion;
  589. ParseDriverVersion(adapterDriverVersionString, &driverVersion);
  590. #endif
  591. if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) &&
  592. !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) {
  593. continue;
  594. }
  595. if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) {
  596. bool deviceMatches = false;
  597. for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
  598. if ((*info[i].mDevices)[j].Equals(adapterDeviceID, nsCaseInsensitiveStringComparator())) {
  599. deviceMatches = true;
  600. break;
  601. }
  602. }
  603. if (!deviceMatches) {
  604. continue;
  605. }
  606. }
  607. bool match = false;
  608. if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) {
  609. continue;
  610. }
  611. if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) {
  612. continue;
  613. }
  614. if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) {
  615. continue;
  616. }
  617. if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) {
  618. continue;
  619. }
  620. #ifdef XP_WIN
  621. switch (info[i].mComparisonOp) {
  622. case DRIVER_LESS_THAN:
  623. match = driverVersion < info[i].mDriverVersion;
  624. break;
  625. case DRIVER_BUILD_ID_LESS_THAN:
  626. match = (driverVersion & 0xFFFF) < info[i].mDriverVersion;
  627. break;
  628. case DRIVER_LESS_THAN_OR_EQUAL:
  629. match = driverVersion <= info[i].mDriverVersion;
  630. break;
  631. case DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL:
  632. match = (driverVersion & 0xFFFF) <= info[i].mDriverVersion;
  633. break;
  634. case DRIVER_GREATER_THAN:
  635. match = driverVersion > info[i].mDriverVersion;
  636. break;
  637. case DRIVER_GREATER_THAN_OR_EQUAL:
  638. match = driverVersion >= info[i].mDriverVersion;
  639. break;
  640. case DRIVER_EQUAL:
  641. match = driverVersion == info[i].mDriverVersion;
  642. break;
  643. case DRIVER_NOT_EQUAL:
  644. match = driverVersion != info[i].mDriverVersion;
  645. break;
  646. case DRIVER_BETWEEN_EXCLUSIVE:
  647. match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
  648. break;
  649. case DRIVER_BETWEEN_INCLUSIVE:
  650. match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax;
  651. break;
  652. case DRIVER_BETWEEN_INCLUSIVE_START:
  653. match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
  654. break;
  655. case DRIVER_COMPARISON_IGNORED:
  656. // We don't have a comparison op, so we match everything.
  657. match = true;
  658. break;
  659. default:
  660. NS_WARNING("Bogus op in GfxDriverInfo");
  661. break;
  662. }
  663. #else
  664. // We don't care what driver version it was. We only check OS version and if
  665. // the device matches.
  666. match = true;
  667. #endif
  668. if (match || info[i].mDriverVersion == GfxDriverInfo::allDriverVersions) {
  669. if (info[i].mFeature == GfxDriverInfo::allFeatures ||
  670. info[i].mFeature == aFeature)
  671. {
  672. status = info[i].mFeatureStatus;
  673. if (!info[i].mRuleId.IsEmpty()) {
  674. aFailureId = info[i].mRuleId.get();
  675. } else {
  676. aFailureId = "FEATURE_FAILURE_DL_BLACKLIST_NO_ID";
  677. }
  678. break;
  679. }
  680. }
  681. }
  682. #if defined(XP_WIN)
  683. // As a very special case, we block D2D on machines with an NVidia 310M GPU
  684. // as either the primary or secondary adapter. D2D is also blocked when the
  685. // NV 310M is the primary adapter (using the standard blocklisting mechanism).
  686. // If the primary GPU already matched something in the blocklist then we
  687. // ignore this special rule. See bug 1008759.
  688. if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN &&
  689. (aFeature == nsIGfxInfo::FEATURE_DIRECT2D)) {
  690. nsAutoString adapterVendorID2;
  691. nsAutoString adapterDeviceID2;
  692. if ((!NS_FAILED(GetAdapterVendorID2(adapterVendorID2))) &&
  693. (!NS_FAILED(GetAdapterDeviceID2(adapterDeviceID2))))
  694. {
  695. nsAString &nvVendorID = (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA);
  696. const nsString nv310mDeviceId = NS_LITERAL_STRING("0x0A70");
  697. if (nvVendorID.Equals(adapterVendorID2, nsCaseInsensitiveStringComparator()) &&
  698. nv310mDeviceId.Equals(adapterDeviceID2, nsCaseInsensitiveStringComparator())) {
  699. status = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
  700. aFailureId = "FEATURE_FAILURE_D2D_NV310M_BLOCK";
  701. }
  702. }
  703. }
  704. // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
  705. // back to the Windows handler, so we must handle this here.
  706. if (status == FEATURE_BLOCKED_DRIVER_VERSION) {
  707. if (info[i].mSuggestedVersion) {
  708. aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion);
  709. } else if (info[i].mComparisonOp == DRIVER_LESS_THAN &&
  710. info[i].mDriverVersion != GfxDriverInfo::allDriverVersions)
  711. {
  712. aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld",
  713. (info[i].mDriverVersion & 0xffff000000000000) >> 48,
  714. (info[i].mDriverVersion & 0x0000ffff00000000) >> 32,
  715. (info[i].mDriverVersion & 0x00000000ffff0000) >> 16,
  716. (info[i].mDriverVersion & 0x000000000000ffff));
  717. }
  718. }
  719. #endif
  720. return status;
  721. }
  722. nsresult
  723. GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature,
  724. int32_t* aStatus,
  725. nsAString& aSuggestedVersion,
  726. const nsTArray<GfxDriverInfo>& aDriverInfo,
  727. nsACString& aFailureId,
  728. OperatingSystem* aOS /* = nullptr */)
  729. {
  730. if (aFeature <= 0) {
  731. gfxWarning() << "Invalid feature <= 0";
  732. return NS_OK;
  733. }
  734. if (*aStatus != nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
  735. // Terminate now with the status determined by the derived type (OS-specific
  736. // code).
  737. return NS_OK;
  738. }
  739. if (mShutdownOccurred) {
  740. // This is futile; we've already commenced shutdown and our blocklists have
  741. // been deleted. We may want to look into resurrecting the blocklist instead
  742. // but for now, just don't even go there.
  743. return NS_OK;
  744. }
  745. // If an operating system was provided by the derived GetFeatureStatusImpl,
  746. // grab it here. Otherwise, the OS is unknown.
  747. OperatingSystem os = (aOS ? *aOS : OperatingSystem::Unknown);
  748. nsAutoString adapterVendorID;
  749. nsAutoString adapterDeviceID;
  750. nsAutoString adapterDriverVersionString;
  751. if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
  752. NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
  753. NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
  754. {
  755. aFailureId = "FEATURE_FAILURE_CANT_RESOLVE_ADAPTER";
  756. *aStatus = FEATURE_BLOCKED_DEVICE;
  757. return NS_OK;
  758. }
  759. // Check if the device is blocked from the downloaded blocklist. If not, check
  760. // the static list after that. This order is used so that we can later escape
  761. // out of static blocks (i.e. if we were wrong or something was patched, we
  762. // can back out our static block without doing a release).
  763. int32_t status;
  764. if (aDriverInfo.Length()) {
  765. status = FindBlocklistedDeviceInList(aDriverInfo, aSuggestedVersion, aFeature, aFailureId, os);
  766. } else {
  767. if (!mDriverInfo) {
  768. mDriverInfo = new nsTArray<GfxDriverInfo>();
  769. }
  770. status = FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion, aFeature, aFailureId, os);
  771. }
  772. // It's now done being processed. It's safe to set the status to STATUS_OK.
  773. if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
  774. *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
  775. } else {
  776. *aStatus = status;
  777. }
  778. return NS_OK;
  779. }
  780. NS_IMETHODIMP
  781. GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature,
  782. nsAString& aVersion)
  783. {
  784. nsCString version;
  785. if (GetPrefValueForDriverVersion(version)) {
  786. aVersion = NS_ConvertASCIItoUTF16(version);
  787. return NS_OK;
  788. }
  789. int32_t status;
  790. nsCString discardFailureId;
  791. nsTArray<GfxDriverInfo> driverInfo;
  792. return GetFeatureStatusImpl(aFeature, &status, aVersion, driverInfo, discardFailureId);
  793. }
  794. NS_IMETHODIMP
  795. GfxInfoBase::GetWebGLParameter(const nsAString& aParam,
  796. nsAString& aResult)
  797. {
  798. return GfxInfoWebGL::GetWebGLParameter(aParam, aResult);
  799. }
  800. void
  801. GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo)
  802. {
  803. int32_t features[] = {
  804. nsIGfxInfo::FEATURE_DIRECT2D,
  805. nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
  806. nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
  807. nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
  808. nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
  809. nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE,
  810. nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
  811. nsIGfxInfo::FEATURE_OPENGL_LAYERS,
  812. nsIGfxInfo::FEATURE_WEBGL_OPENGL,
  813. nsIGfxInfo::FEATURE_WEBGL_ANGLE,
  814. nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE,
  815. nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE,
  816. nsIGfxInfo::FEATURE_WEBGL_MSAA,
  817. nsIGfxInfo::FEATURE_STAGEFRIGHT,
  818. nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION,
  819. nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
  820. 0
  821. };
  822. // For every feature we know about, we evaluate whether this blacklist has a
  823. // non-STATUS_OK status. If it does, we set the pref we evaluate in
  824. // GetFeatureStatus above, so we don't need to hold on to this blacklist
  825. // anywhere permanent.
  826. int i = 0;
  827. while (features[i]) {
  828. int32_t status;
  829. nsCString failureId;
  830. nsAutoString suggestedVersion;
  831. if (NS_SUCCEEDED(GetFeatureStatusImpl(features[i], &status,
  832. suggestedVersion,
  833. aDriverInfo,
  834. failureId))) {
  835. switch (status) {
  836. default:
  837. case nsIGfxInfo::FEATURE_STATUS_OK:
  838. RemovePrefForFeature(features[i]);
  839. break;
  840. case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION:
  841. if (!suggestedVersion.IsEmpty()) {
  842. SetPrefValueForDriverVersion(suggestedVersion);
  843. } else {
  844. RemovePrefForDriverVersion();
  845. }
  846. MOZ_FALLTHROUGH;
  847. case nsIGfxInfo::FEATURE_BLOCKED_MISMATCHED_VERSION:
  848. case nsIGfxInfo::FEATURE_BLOCKED_DEVICE:
  849. case nsIGfxInfo::FEATURE_DISCOURAGED:
  850. case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION:
  851. SetPrefValueForFeature(features[i], status, failureId);
  852. break;
  853. }
  854. }
  855. ++i;
  856. }
  857. }
  858. NS_IMETHODIMP_(void)
  859. GfxInfoBase::LogFailure(const nsACString &failure)
  860. {
  861. // gfxCriticalError has a mutex lock of its own, so we may not actually
  862. // need this lock. ::GetFailures() accesses the data but the LogForwarder
  863. // will not return the copy of the logs unless it can get the same lock
  864. // that gfxCriticalError uses. Still, that is so much of an implementation
  865. // detail that it's nicer to just add an extra lock here and in ::GetFailures()
  866. MutexAutoLock lock(mMutex);
  867. // By default, gfxCriticalError asserts; make it not assert in this case.
  868. gfxCriticalError(CriticalLog::DefaultOptions(false)) << "(LF) " << failure.BeginReading();
  869. }
  870. /* XPConnect method of returning arrays is very ugly. Would not recommend. */
  871. NS_IMETHODIMP GfxInfoBase::GetFailures(uint32_t* failureCount,
  872. int32_t** indices,
  873. char ***failures)
  874. {
  875. MutexAutoLock lock(mMutex);
  876. NS_ENSURE_ARG_POINTER(failureCount);
  877. NS_ENSURE_ARG_POINTER(failures);
  878. *failures = nullptr;
  879. *failureCount = 0;
  880. // indices is "allowed" to be null, the caller may not care about them,
  881. // although calling from JS doesn't seem to get us there.
  882. if (indices) *indices = nullptr;
  883. LogForwarder* logForwarder = Factory::GetLogForwarder();
  884. if (!logForwarder) {
  885. return NS_ERROR_UNEXPECTED;
  886. }
  887. // There are two stirng copies in this method, starting with this one. We are
  888. // assuming this is not a big deal, as the size of the array should be small
  889. // and the strings in it should be small as well (the error messages in the
  890. // code.) The second copy happens with the Clone() calls. Technically,
  891. // we don't need the mutex lock after the StringVectorCopy() call.
  892. LoggingRecord loggedStrings = logForwarder->LoggingRecordCopy();
  893. *failureCount = loggedStrings.size();
  894. if (*failureCount != 0) {
  895. *failures = (char**)moz_xmalloc(*failureCount * sizeof(char*));
  896. if (!(*failures)) {
  897. return NS_ERROR_OUT_OF_MEMORY;
  898. }
  899. if (indices) {
  900. *indices = (int32_t*)moz_xmalloc(*failureCount * sizeof(int32_t));
  901. if (!(*indices)) {
  902. free(*failures);
  903. *failures = nullptr;
  904. return NS_ERROR_OUT_OF_MEMORY;
  905. }
  906. }
  907. /* copy over the failure messages into the array we just allocated */
  908. LoggingRecord::const_iterator it;
  909. uint32_t i=0;
  910. for(it = loggedStrings.begin() ; it != loggedStrings.end(); ++it, i++) {
  911. (*failures)[i] = (char*)nsMemory::Clone(Get<1>(*it).c_str(), Get<1>(*it).size() + 1);
  912. if (indices) (*indices)[i] = Get<0>(*it);
  913. if (!(*failures)[i]) {
  914. /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
  915. NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, (*failures));
  916. *failureCount = i;
  917. return NS_ERROR_OUT_OF_MEMORY;
  918. }
  919. }
  920. }
  921. return NS_OK;
  922. }
  923. nsTArray<GfxInfoCollectorBase*> *sCollectors;
  924. static void
  925. InitCollectors()
  926. {
  927. if (!sCollectors)
  928. sCollectors = new nsTArray<GfxInfoCollectorBase*>;
  929. }
  930. nsresult GfxInfoBase::GetInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
  931. {
  932. InitCollectors();
  933. InfoObject obj(aCx);
  934. for (uint32_t i = 0; i < sCollectors->Length(); i++) {
  935. (*sCollectors)[i]->GetInfo(obj);
  936. }
  937. // Some example property definitions
  938. // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
  939. // obj.DefineProperty("renderer", mRendererIDsString);
  940. // obj.DefineProperty("five", 5);
  941. if (!obj.mOk) {
  942. return NS_ERROR_FAILURE;
  943. }
  944. aResult.setObject(*obj.mObj);
  945. return NS_OK;
  946. }
  947. nsAutoCString gBaseAppVersion;
  948. const nsCString&
  949. GfxInfoBase::GetApplicationVersion()
  950. {
  951. static bool versionInitialized = false;
  952. if (!versionInitialized) {
  953. // If we fail to get the version, we will not try again.
  954. versionInitialized = true;
  955. // Get the version from xpcom/system/nsIXULAppInfo.idl
  956. nsCOMPtr<nsIXULAppInfo> app = do_GetService("@mozilla.org/xre/app-info;1");
  957. if (app) {
  958. app->GetVersion(gBaseAppVersion);
  959. }
  960. }
  961. return gBaseAppVersion;
  962. }
  963. void
  964. GfxInfoBase::AddCollector(GfxInfoCollectorBase* collector)
  965. {
  966. InitCollectors();
  967. sCollectors->AppendElement(collector);
  968. }
  969. void
  970. GfxInfoBase::RemoveCollector(GfxInfoCollectorBase* collector)
  971. {
  972. InitCollectors();
  973. for (uint32_t i = 0; i < sCollectors->Length(); i++) {
  974. if ((*sCollectors)[i] == collector) {
  975. sCollectors->RemoveElementAt(i);
  976. break;
  977. }
  978. }
  979. if (sCollectors->IsEmpty()) {
  980. delete sCollectors;
  981. sCollectors = nullptr;
  982. }
  983. }
  984. NS_IMETHODIMP
  985. GfxInfoBase::GetMonitors(JSContext* aCx, JS::MutableHandleValue aResult)
  986. {
  987. JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
  988. nsresult rv = FindMonitors(aCx, array);
  989. if (NS_FAILED(rv)) {
  990. return rv;
  991. }
  992. aResult.setObject(*array);
  993. return NS_OK;
  994. }
  995. static const char*
  996. GetLayersBackendName(layers::LayersBackend aBackend)
  997. {
  998. switch (aBackend) {
  999. case layers::LayersBackend::LAYERS_NONE:
  1000. return "none";
  1001. case layers::LayersBackend::LAYERS_OPENGL:
  1002. return "opengl";
  1003. case layers::LayersBackend::LAYERS_D3D9:
  1004. return "d3d9";
  1005. case layers::LayersBackend::LAYERS_D3D11:
  1006. return "d3d11";
  1007. case layers::LayersBackend::LAYERS_CLIENT:
  1008. return "client";
  1009. case layers::LayersBackend::LAYERS_BASIC:
  1010. return "basic";
  1011. default:
  1012. MOZ_ASSERT_UNREACHABLE("unknown layers backend");
  1013. return "unknown";
  1014. }
  1015. }
  1016. static inline bool
  1017. SetJSPropertyString(JSContext* aCx, JS::Handle<JSObject*> aObj,
  1018. const char* aProp, const char* aString)
  1019. {
  1020. JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, aString));
  1021. if (!str) {
  1022. return false;
  1023. }
  1024. JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
  1025. return JS_SetProperty(aCx, aObj, aProp, val);
  1026. }
  1027. template <typename T>
  1028. static inline bool
  1029. AppendJSElement(JSContext* aCx, JS::Handle<JSObject*> aObj, const T& aValue)
  1030. {
  1031. uint32_t index;
  1032. if (!JS_GetArrayLength(aCx, aObj, &index)) {
  1033. return false;
  1034. }
  1035. return JS_SetElement(aCx, aObj, index, aValue);
  1036. }
  1037. nsresult
  1038. GfxInfoBase::GetFeatures(JSContext* aCx, JS::MutableHandle<JS::Value> aOut)
  1039. {
  1040. JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
  1041. if (!obj) {
  1042. return NS_ERROR_OUT_OF_MEMORY;
  1043. }
  1044. aOut.setObject(*obj);
  1045. layers::LayersBackend backend = gfxPlatform::Initialized()
  1046. ? gfxPlatform::GetPlatform()->GetCompositorBackend()
  1047. : layers::LayersBackend::LAYERS_NONE;
  1048. const char* backendName = GetLayersBackendName(backend);
  1049. SetJSPropertyString(aCx, obj, "compositor", backendName);
  1050. // If graphics isn't initialized yet, just stop now.
  1051. if (!gfxPlatform::Initialized()) {
  1052. return NS_OK;
  1053. }
  1054. DescribeFeatures(aCx, obj);
  1055. return NS_OK;
  1056. }
  1057. nsresult GfxInfoBase::GetFeatureLog(JSContext* aCx, JS::MutableHandle<JS::Value> aOut)
  1058. {
  1059. JS::Rooted<JSObject*> containerObj(aCx, JS_NewPlainObject(aCx));
  1060. if (!containerObj) {
  1061. return NS_ERROR_OUT_OF_MEMORY;
  1062. }
  1063. aOut.setObject(*containerObj);
  1064. JS::Rooted<JSObject*> featureArray(aCx, JS_NewArrayObject(aCx, 0));
  1065. if (!featureArray) {
  1066. return NS_ERROR_OUT_OF_MEMORY;
  1067. }
  1068. // Collect features.
  1069. gfxConfig::ForEachFeature([&](const char* aName,
  1070. const char* aDescription,
  1071. FeatureState& aFeature) -> void {
  1072. JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
  1073. if (!obj) {
  1074. return;
  1075. }
  1076. if (!SetJSPropertyString(aCx, obj, "name", aName) ||
  1077. !SetJSPropertyString(aCx, obj, "description", aDescription) ||
  1078. !SetJSPropertyString(aCx, obj, "status", FeatureStatusToString(aFeature.GetValue())))
  1079. {
  1080. return;
  1081. }
  1082. JS::Rooted<JS::Value> log(aCx);
  1083. if (!BuildFeatureStateLog(aCx, aFeature, &log)) {
  1084. return;
  1085. }
  1086. if (!JS_SetProperty(aCx, obj, "log", log)) {
  1087. return;
  1088. }
  1089. if (!AppendJSElement(aCx, featureArray, obj)) {
  1090. return;
  1091. }
  1092. });
  1093. JS::Rooted<JSObject*> fallbackArray(aCx, JS_NewArrayObject(aCx, 0));
  1094. if (!fallbackArray) {
  1095. return NS_ERROR_OUT_OF_MEMORY;
  1096. }
  1097. // Collect fallbacks.
  1098. gfxConfig::ForEachFallback([&](const char* aName, const char* aMessage) -> void {
  1099. JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
  1100. if (!obj) {
  1101. return;
  1102. }
  1103. if (!SetJSPropertyString(aCx, obj, "name", aName) ||
  1104. !SetJSPropertyString(aCx, obj, "message", aMessage))
  1105. {
  1106. return;
  1107. }
  1108. if (!AppendJSElement(aCx, fallbackArray, obj)) {
  1109. return;
  1110. }
  1111. });
  1112. JS::Rooted<JS::Value> val(aCx);
  1113. val = JS::ObjectValue(*featureArray);
  1114. JS_SetProperty(aCx, containerObj, "features", val);
  1115. val = JS::ObjectValue(*fallbackArray);
  1116. JS_SetProperty(aCx, containerObj, "fallbacks", val);
  1117. return NS_OK;
  1118. }
  1119. bool
  1120. GfxInfoBase::BuildFeatureStateLog(JSContext* aCx, const FeatureState& aFeature,
  1121. JS::MutableHandle<JS::Value> aOut)
  1122. {
  1123. JS::Rooted<JSObject*> log(aCx, JS_NewArrayObject(aCx, 0));
  1124. if (!log) {
  1125. return false;
  1126. }
  1127. aOut.setObject(*log);
  1128. aFeature.ForEachStatusChange([&](const char* aType,
  1129. FeatureStatus aStatus,
  1130. const char* aMessage) -> void {
  1131. JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
  1132. if (!obj) {
  1133. return;
  1134. }
  1135. if (!SetJSPropertyString(aCx, obj, "type", aType) ||
  1136. !SetJSPropertyString(aCx, obj, "status", FeatureStatusToString(aStatus)) ||
  1137. (aMessage && !SetJSPropertyString(aCx, obj, "message", aMessage)))
  1138. {
  1139. return;
  1140. }
  1141. if (!AppendJSElement(aCx, log, obj)) {
  1142. return;
  1143. }
  1144. });
  1145. return true;
  1146. }
  1147. void
  1148. GfxInfoBase::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj)
  1149. {
  1150. }
  1151. bool
  1152. GfxInfoBase::InitFeatureObject(JSContext* aCx,
  1153. JS::Handle<JSObject*> aContainer,
  1154. const char* aName,
  1155. int32_t aFeature,
  1156. Maybe<mozilla::gfx::FeatureStatus> aFeatureStatus,
  1157. JS::MutableHandle<JSObject*> aOutObj)
  1158. {
  1159. JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
  1160. if (!obj) {
  1161. return false;
  1162. }
  1163. nsCString failureId = NS_LITERAL_CSTRING("OK");
  1164. int32_t unused;
  1165. if (!NS_SUCCEEDED(GetFeatureStatus(aFeature, failureId, &unused))) {
  1166. return false;
  1167. }
  1168. // Set "status".
  1169. if (aFeatureStatus) {
  1170. const char* status = FeatureStatusToString(aFeatureStatus.value());
  1171. JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, status));
  1172. JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
  1173. JS_SetProperty(aCx, obj, "status", val);
  1174. }
  1175. // Add the feature object to the container.
  1176. {
  1177. JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*obj));
  1178. JS_SetProperty(aCx, aContainer, aName, val);
  1179. }
  1180. aOutObj.set(obj);
  1181. return true;
  1182. }
  1183. nsresult
  1184. GfxInfoBase::GetActiveCrashGuards(JSContext* aCx, JS::MutableHandle<JS::Value> aOut)
  1185. {
  1186. JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
  1187. if (!array) {
  1188. return NS_ERROR_OUT_OF_MEMORY;
  1189. }
  1190. aOut.setObject(*array);
  1191. DriverCrashGuard::ForEachActiveCrashGuard([&](const char* aName,
  1192. const char* aPrefName) -> void {
  1193. JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
  1194. if (!obj) {
  1195. return;
  1196. }
  1197. if (!SetJSPropertyString(aCx, obj, "type", aName)) {
  1198. return;
  1199. }
  1200. if (!SetJSPropertyString(aCx, obj, "prefName", aPrefName)) {
  1201. return;
  1202. }
  1203. if (!AppendJSElement(aCx, array, obj)) {
  1204. return;
  1205. }
  1206. });
  1207. return NS_OK;
  1208. }
  1209. NS_IMETHODIMP
  1210. GfxInfoBase::GetContentBackend(nsAString & aContentBackend)
  1211. {
  1212. BackendType backend = gfxPlatform::GetPlatform()->GetDefaultContentBackend();
  1213. nsString outStr;
  1214. switch (backend) {
  1215. case BackendType::DIRECT2D1_1: {
  1216. outStr.AppendPrintf("Direct2D 1.1");
  1217. break;
  1218. }
  1219. case BackendType::SKIA: {
  1220. outStr.AppendPrintf("Skia");
  1221. break;
  1222. }
  1223. case BackendType::CAIRO: {
  1224. outStr.AppendPrintf("Cairo");
  1225. break;
  1226. }
  1227. default:
  1228. return NS_ERROR_FAILURE;
  1229. }
  1230. aContentBackend.Assign(outStr);
  1231. return NS_OK;
  1232. }
  1233. GfxInfoCollectorBase::GfxInfoCollectorBase()
  1234. {
  1235. GfxInfoBase::AddCollector(this);
  1236. }
  1237. GfxInfoCollectorBase::~GfxInfoCollectorBase()
  1238. {
  1239. GfxInfoBase::RemoveCollector(this);
  1240. }