atom_api_app.cc 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/api/atom_api_app.h"
  5. #include <string>
  6. #include <vector>
  7. #include "base/command_line.h"
  8. #include "base/environment.h"
  9. #include "base/files/file_path.h"
  10. #include "base/files/file_util.h"
  11. #include "base/optional.h"
  12. #include "base/path_service.h"
  13. #include "base/system/sys_info.h"
  14. #include "chrome/browser/browser_process.h"
  15. #include "chrome/browser/icon_manager.h"
  16. #include "chrome/common/chrome_paths.h"
  17. #include "content/browser/gpu/compositor_util.h" // nogncheck
  18. #include "content/browser/gpu/gpu_data_manager_impl.h" // nogncheck
  19. #include "content/public/browser/browser_accessibility_state.h"
  20. #include "content/public/browser/browser_child_process_host.h"
  21. #include "content/public/browser/child_process_data.h"
  22. #include "content/public/browser/client_certificate_delegate.h"
  23. #include "content/public/browser/gpu_data_manager.h"
  24. #include "content/public/browser/render_frame_host.h"
  25. #include "content/public/common/content_switches.h"
  26. #include "media/audio/audio_manager.h"
  27. #include "native_mate/object_template_builder.h"
  28. #include "net/ssl/client_cert_identity.h"
  29. #include "net/ssl/ssl_cert_request_info.h"
  30. #include "services/service_manager/sandbox/switches.h"
  31. #include "shell/browser/api/atom_api_menu.h"
  32. #include "shell/browser/api/atom_api_session.h"
  33. #include "shell/browser/api/atom_api_web_contents.h"
  34. #include "shell/browser/api/gpuinfo_manager.h"
  35. #include "shell/browser/atom_browser_context.h"
  36. #include "shell/browser/atom_browser_main_parts.h"
  37. #include "shell/browser/atom_paths.h"
  38. #include "shell/browser/login_handler.h"
  39. #include "shell/browser/relauncher.h"
  40. #include "shell/common/application_info.h"
  41. #include "shell/common/atom_command_line.h"
  42. #include "shell/common/native_mate_converters/callback.h"
  43. #include "shell/common/native_mate_converters/file_path_converter.h"
  44. #include "shell/common/native_mate_converters/gurl_converter.h"
  45. #include "shell/common/native_mate_converters/image_converter.h"
  46. #include "shell/common/native_mate_converters/net_converter.h"
  47. #include "shell/common/native_mate_converters/network_converter.h"
  48. #include "shell/common/native_mate_converters/once_callback.h"
  49. #include "shell/common/native_mate_converters/value_converter.h"
  50. #include "shell/common/node_includes.h"
  51. #include "shell/common/options_switches.h"
  52. #include "ui/base/l10n/l10n_util.h"
  53. #include "ui/gfx/image/image.h"
  54. #if defined(OS_WIN)
  55. #include "base/strings/utf_string_conversions.h"
  56. #include "shell/browser/ui/win/jump_list.h"
  57. #endif
  58. #if defined(OS_MACOSX)
  59. #include <CoreFoundation/CoreFoundation.h>
  60. #include "shell/browser/ui/cocoa/atom_bundle_mover.h"
  61. #endif
  62. using electron::Browser;
  63. namespace mate {
  64. #if defined(OS_WIN)
  65. template <>
  66. struct Converter<electron::ProcessIntegrityLevel> {
  67. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  68. electron::ProcessIntegrityLevel value) {
  69. switch (value) {
  70. case electron::ProcessIntegrityLevel::Untrusted:
  71. return mate::StringToV8(isolate, "untrusted");
  72. case electron::ProcessIntegrityLevel::Low:
  73. return mate::StringToV8(isolate, "low");
  74. case electron::ProcessIntegrityLevel::Medium:
  75. return mate::StringToV8(isolate, "medium");
  76. case electron::ProcessIntegrityLevel::High:
  77. return mate::StringToV8(isolate, "high");
  78. default:
  79. return mate::StringToV8(isolate, "unknown");
  80. }
  81. }
  82. };
  83. template <>
  84. struct Converter<Browser::UserTask> {
  85. static bool FromV8(v8::Isolate* isolate,
  86. v8::Local<v8::Value> val,
  87. Browser::UserTask* out) {
  88. mate::Dictionary dict;
  89. if (!ConvertFromV8(isolate, val, &dict))
  90. return false;
  91. if (!dict.Get("program", &(out->program)) ||
  92. !dict.Get("title", &(out->title)))
  93. return false;
  94. if (dict.Get("iconPath", &(out->icon_path)) &&
  95. !dict.Get("iconIndex", &(out->icon_index)))
  96. return false;
  97. dict.Get("arguments", &(out->arguments));
  98. dict.Get("description", &(out->description));
  99. dict.Get("workingDirectory", &(out->working_dir));
  100. return true;
  101. }
  102. };
  103. using electron::JumpListCategory;
  104. using electron::JumpListItem;
  105. using electron::JumpListResult;
  106. template <>
  107. struct Converter<JumpListItem::Type> {
  108. static bool FromV8(v8::Isolate* isolate,
  109. v8::Local<v8::Value> val,
  110. JumpListItem::Type* out) {
  111. std::string item_type;
  112. if (!ConvertFromV8(isolate, val, &item_type))
  113. return false;
  114. if (item_type == "task")
  115. *out = JumpListItem::Type::TASK;
  116. else if (item_type == "separator")
  117. *out = JumpListItem::Type::SEPARATOR;
  118. else if (item_type == "file")
  119. *out = JumpListItem::Type::FILE;
  120. else
  121. return false;
  122. return true;
  123. }
  124. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  125. JumpListItem::Type val) {
  126. std::string item_type;
  127. switch (val) {
  128. case JumpListItem::Type::TASK:
  129. item_type = "task";
  130. break;
  131. case JumpListItem::Type::SEPARATOR:
  132. item_type = "separator";
  133. break;
  134. case JumpListItem::Type::FILE:
  135. item_type = "file";
  136. break;
  137. }
  138. return mate::ConvertToV8(isolate, item_type);
  139. }
  140. };
  141. template <>
  142. struct Converter<JumpListItem> {
  143. static bool FromV8(v8::Isolate* isolate,
  144. v8::Local<v8::Value> val,
  145. JumpListItem* out) {
  146. mate::Dictionary dict;
  147. if (!ConvertFromV8(isolate, val, &dict))
  148. return false;
  149. if (!dict.Get("type", &(out->type)))
  150. return false;
  151. switch (out->type) {
  152. case JumpListItem::Type::TASK:
  153. if (!dict.Get("program", &(out->path)) ||
  154. !dict.Get("title", &(out->title)))
  155. return false;
  156. if (dict.Get("iconPath", &(out->icon_path)) &&
  157. !dict.Get("iconIndex", &(out->icon_index)))
  158. return false;
  159. dict.Get("args", &(out->arguments));
  160. dict.Get("description", &(out->description));
  161. dict.Get("workingDirectory", &(out->working_dir));
  162. return true;
  163. case JumpListItem::Type::SEPARATOR:
  164. return true;
  165. case JumpListItem::Type::FILE:
  166. return dict.Get("path", &(out->path));
  167. }
  168. assert(false);
  169. return false;
  170. }
  171. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  172. const JumpListItem& val) {
  173. mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
  174. dict.Set("type", val.type);
  175. switch (val.type) {
  176. case JumpListItem::Type::TASK:
  177. dict.Set("program", val.path);
  178. dict.Set("args", val.arguments);
  179. dict.Set("title", val.title);
  180. dict.Set("iconPath", val.icon_path);
  181. dict.Set("iconIndex", val.icon_index);
  182. dict.Set("description", val.description);
  183. dict.Set("workingDirectory", val.working_dir);
  184. break;
  185. case JumpListItem::Type::SEPARATOR:
  186. break;
  187. case JumpListItem::Type::FILE:
  188. dict.Set("path", val.path);
  189. break;
  190. }
  191. return dict.GetHandle();
  192. }
  193. };
  194. template <>
  195. struct Converter<JumpListCategory::Type> {
  196. static bool FromV8(v8::Isolate* isolate,
  197. v8::Local<v8::Value> val,
  198. JumpListCategory::Type* out) {
  199. std::string category_type;
  200. if (!ConvertFromV8(isolate, val, &category_type))
  201. return false;
  202. if (category_type == "tasks")
  203. *out = JumpListCategory::Type::TASKS;
  204. else if (category_type == "frequent")
  205. *out = JumpListCategory::Type::FREQUENT;
  206. else if (category_type == "recent")
  207. *out = JumpListCategory::Type::RECENT;
  208. else if (category_type == "custom")
  209. *out = JumpListCategory::Type::CUSTOM;
  210. else
  211. return false;
  212. return true;
  213. }
  214. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  215. JumpListCategory::Type val) {
  216. std::string category_type;
  217. switch (val) {
  218. case JumpListCategory::Type::TASKS:
  219. category_type = "tasks";
  220. break;
  221. case JumpListCategory::Type::FREQUENT:
  222. category_type = "frequent";
  223. break;
  224. case JumpListCategory::Type::RECENT:
  225. category_type = "recent";
  226. break;
  227. case JumpListCategory::Type::CUSTOM:
  228. category_type = "custom";
  229. break;
  230. }
  231. return mate::ConvertToV8(isolate, category_type);
  232. }
  233. };
  234. template <>
  235. struct Converter<JumpListCategory> {
  236. static bool FromV8(v8::Isolate* isolate,
  237. v8::Local<v8::Value> val,
  238. JumpListCategory* out) {
  239. mate::Dictionary dict;
  240. if (!ConvertFromV8(isolate, val, &dict))
  241. return false;
  242. if (dict.Get("name", &(out->name)) && out->name.empty())
  243. return false;
  244. if (!dict.Get("type", &(out->type))) {
  245. if (out->name.empty())
  246. out->type = JumpListCategory::Type::TASKS;
  247. else
  248. out->type = JumpListCategory::Type::CUSTOM;
  249. }
  250. if ((out->type == JumpListCategory::Type::TASKS) ||
  251. (out->type == JumpListCategory::Type::CUSTOM)) {
  252. if (!dict.Get("items", &(out->items)))
  253. return false;
  254. }
  255. return true;
  256. }
  257. };
  258. // static
  259. template <>
  260. struct Converter<JumpListResult> {
  261. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, JumpListResult val) {
  262. std::string result_code;
  263. switch (val) {
  264. case JumpListResult::SUCCESS:
  265. result_code = "ok";
  266. break;
  267. case JumpListResult::ARGUMENT_ERROR:
  268. result_code = "argumentError";
  269. break;
  270. case JumpListResult::GENERIC_ERROR:
  271. result_code = "error";
  272. break;
  273. case JumpListResult::CUSTOM_CATEGORY_SEPARATOR_ERROR:
  274. result_code = "invalidSeparatorError";
  275. break;
  276. case JumpListResult::MISSING_FILE_TYPE_REGISTRATION_ERROR:
  277. result_code = "fileTypeRegistrationError";
  278. break;
  279. case JumpListResult::CUSTOM_CATEGORY_ACCESS_DENIED_ERROR:
  280. result_code = "customCategoryAccessDeniedError";
  281. break;
  282. }
  283. return ConvertToV8(isolate, result_code);
  284. }
  285. };
  286. #endif
  287. template <>
  288. struct Converter<Browser::LoginItemSettings> {
  289. static bool FromV8(v8::Isolate* isolate,
  290. v8::Local<v8::Value> val,
  291. Browser::LoginItemSettings* out) {
  292. mate::Dictionary dict;
  293. if (!ConvertFromV8(isolate, val, &dict))
  294. return false;
  295. dict.Get("openAtLogin", &(out->open_at_login));
  296. dict.Get("openAsHidden", &(out->open_as_hidden));
  297. dict.Get("path", &(out->path));
  298. dict.Get("args", &(out->args));
  299. return true;
  300. }
  301. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  302. Browser::LoginItemSettings val) {
  303. mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
  304. dict.Set("openAtLogin", val.open_at_login);
  305. dict.Set("openAsHidden", val.open_as_hidden);
  306. dict.Set("restoreState", val.restore_state);
  307. dict.Set("wasOpenedAtLogin", val.opened_at_login);
  308. dict.Set("wasOpenedAsHidden", val.opened_as_hidden);
  309. return dict.GetHandle();
  310. }
  311. };
  312. template <>
  313. struct Converter<content::CertificateRequestResultType> {
  314. static bool FromV8(v8::Isolate* isolate,
  315. v8::Local<v8::Value> val,
  316. content::CertificateRequestResultType* out) {
  317. bool b;
  318. if (!ConvertFromV8(isolate, val, &b))
  319. return false;
  320. *out = b ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE
  321. : content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
  322. return true;
  323. }
  324. };
  325. } // namespace mate
  326. namespace electron {
  327. namespace api {
  328. namespace {
  329. IconLoader::IconSize GetIconSizeByString(const std::string& size) {
  330. if (size == "small") {
  331. return IconLoader::IconSize::SMALL;
  332. } else if (size == "large") {
  333. return IconLoader::IconSize::LARGE;
  334. }
  335. return IconLoader::IconSize::NORMAL;
  336. }
  337. // Return the path constant from string.
  338. int GetPathConstant(const std::string& name) {
  339. if (name == "appData")
  340. return DIR_APP_DATA;
  341. else if (name == "userData")
  342. return DIR_USER_DATA;
  343. else if (name == "cache")
  344. return DIR_CACHE;
  345. else if (name == "userCache")
  346. return DIR_USER_CACHE;
  347. else if (name == "logs")
  348. return DIR_APP_LOGS;
  349. else if (name == "home")
  350. return base::DIR_HOME;
  351. else if (name == "temp")
  352. return base::DIR_TEMP;
  353. else if (name == "userDesktop" || name == "desktop")
  354. return base::DIR_USER_DESKTOP;
  355. else if (name == "exe")
  356. return base::FILE_EXE;
  357. else if (name == "module")
  358. return base::FILE_MODULE;
  359. else if (name == "documents")
  360. return chrome::DIR_USER_DOCUMENTS;
  361. else if (name == "downloads")
  362. return chrome::DIR_DEFAULT_DOWNLOADS;
  363. else if (name == "music")
  364. return chrome::DIR_USER_MUSIC;
  365. else if (name == "pictures")
  366. return chrome::DIR_USER_PICTURES;
  367. else if (name == "videos")
  368. return chrome::DIR_USER_VIDEOS;
  369. else if (name == "pepperFlashSystemPlugin")
  370. return chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN;
  371. else
  372. return -1;
  373. }
  374. bool NotificationCallbackWrapper(
  375. const base::RepeatingCallback<
  376. void(const base::CommandLine::StringVector& command_line,
  377. const base::FilePath& current_directory)>& callback,
  378. const base::CommandLine::StringVector& cmd,
  379. const base::FilePath& cwd) {
  380. // Make sure the callback is called after app gets ready.
  381. if (Browser::Get()->is_ready()) {
  382. callback.Run(cmd, cwd);
  383. } else {
  384. scoped_refptr<base::SingleThreadTaskRunner> task_runner(
  385. base::ThreadTaskRunnerHandle::Get());
  386. task_runner->PostTask(
  387. FROM_HERE, base::BindOnce(base::IgnoreResult(callback), cmd, cwd));
  388. }
  389. // ProcessSingleton needs to know whether current process is quiting.
  390. return !Browser::Get()->is_shutting_down();
  391. }
  392. void GotPrivateKey(std::shared_ptr<content::ClientCertificateDelegate> delegate,
  393. scoped_refptr<net::X509Certificate> cert,
  394. scoped_refptr<net::SSLPrivateKey> private_key) {
  395. delegate->ContinueWithCertificate(cert, private_key);
  396. }
  397. void OnClientCertificateSelected(
  398. v8::Isolate* isolate,
  399. std::shared_ptr<content::ClientCertificateDelegate> delegate,
  400. std::shared_ptr<net::ClientCertIdentityList> identities,
  401. mate::Arguments* args) {
  402. if (args->Length() == 2) {
  403. delegate->ContinueWithCertificate(nullptr, nullptr);
  404. return;
  405. }
  406. v8::Local<v8::Value> val;
  407. args->GetNext(&val);
  408. if (val->IsNull()) {
  409. delegate->ContinueWithCertificate(nullptr, nullptr);
  410. return;
  411. }
  412. mate::Dictionary cert_data;
  413. if (!mate::ConvertFromV8(isolate, val, &cert_data)) {
  414. args->ThrowError("Must pass valid certificate object.");
  415. return;
  416. }
  417. std::string data;
  418. if (!cert_data.Get("data", &data))
  419. return;
  420. auto certs = net::X509Certificate::CreateCertificateListFromBytes(
  421. data.c_str(), data.length(), net::X509Certificate::FORMAT_AUTO);
  422. if (!certs.empty()) {
  423. scoped_refptr<net::X509Certificate> cert(certs[0].get());
  424. for (size_t i = 0; i < identities->size(); ++i) {
  425. if (cert->EqualsExcludingChain((*identities)[i]->certificate())) {
  426. net::ClientCertIdentity::SelfOwningAcquirePrivateKey(
  427. std::move((*identities)[i]),
  428. base::BindRepeating(&GotPrivateKey, delegate, std::move(cert)));
  429. break;
  430. }
  431. }
  432. }
  433. }
  434. #if defined(USE_NSS_CERTS)
  435. int ImportIntoCertStore(CertificateManagerModel* model,
  436. const base::DictionaryValue& options) {
  437. std::string file_data, cert_path;
  438. base::string16 password;
  439. net::ScopedCERTCertificateList imported_certs;
  440. int rv = -1;
  441. options.GetString("certificate", &cert_path);
  442. options.GetString("password", &password);
  443. if (!cert_path.empty()) {
  444. if (base::ReadFileToString(base::FilePath(cert_path), &file_data)) {
  445. auto module = model->cert_db()->GetPrivateSlot();
  446. rv = model->ImportFromPKCS12(module.get(), file_data, password, true,
  447. &imported_certs);
  448. if (imported_certs.size() > 1) {
  449. auto it = imported_certs.begin();
  450. ++it; // skip first which would be the client certificate.
  451. for (; it != imported_certs.end(); ++it)
  452. rv &= model->SetCertTrust(it->get(), net::CA_CERT,
  453. net::NSSCertDatabase::TRUSTED_SSL);
  454. }
  455. }
  456. }
  457. return rv;
  458. }
  459. #endif
  460. void OnIconDataAvailable(util::Promise promise, gfx::Image icon) {
  461. if (!icon.IsEmpty()) {
  462. promise.Resolve(icon);
  463. } else {
  464. promise.RejectWithErrorMessage("Failed to get file icon.");
  465. }
  466. }
  467. } // namespace
  468. App::App(v8::Isolate* isolate) {
  469. static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this);
  470. Browser::Get()->AddObserver(this);
  471. content::GpuDataManager::GetInstance()->AddObserver(this);
  472. base::ProcessId pid = base::GetCurrentProcId();
  473. auto process_metric = std::make_unique<electron::ProcessMetric>(
  474. content::PROCESS_TYPE_BROWSER, base::GetCurrentProcessHandle(),
  475. base::ProcessMetrics::CreateCurrentProcessMetrics());
  476. app_metrics_[pid] = std::move(process_metric);
  477. Init(isolate);
  478. }
  479. App::~App() {
  480. static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())
  481. ->set_delegate(nullptr);
  482. Browser::Get()->RemoveObserver(this);
  483. content::GpuDataManager::GetInstance()->RemoveObserver(this);
  484. content::BrowserChildProcessObserver::Remove(this);
  485. }
  486. void App::OnBeforeQuit(bool* prevent_default) {
  487. if (Emit("before-quit")) {
  488. *prevent_default = true;
  489. }
  490. }
  491. void App::OnWillQuit(bool* prevent_default) {
  492. if (Emit("will-quit")) {
  493. *prevent_default = true;
  494. }
  495. }
  496. void App::OnWindowAllClosed() {
  497. Emit("window-all-closed");
  498. }
  499. void App::OnQuit() {
  500. int exitCode = AtomBrowserMainParts::Get()->GetExitCode();
  501. Emit("quit", exitCode);
  502. if (process_singleton_) {
  503. process_singleton_->Cleanup();
  504. process_singleton_.reset();
  505. }
  506. }
  507. void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
  508. if (Emit("open-file", file_path)) {
  509. *prevent_default = true;
  510. }
  511. }
  512. void App::OnOpenURL(const std::string& url) {
  513. Emit("open-url", url);
  514. }
  515. void App::OnActivate(bool has_visible_windows) {
  516. Emit("activate", has_visible_windows);
  517. }
  518. void App::OnWillFinishLaunching() {
  519. Emit("will-finish-launching");
  520. }
  521. void App::OnFinishLaunching(const base::DictionaryValue& launch_info) {
  522. #if defined(OS_LINUX)
  523. // Set the application name for audio streams shown in external
  524. // applications. Only affects pulseaudio currently.
  525. media::AudioManager::SetGlobalAppName(Browser::Get()->GetName());
  526. #endif
  527. Emit("ready", launch_info);
  528. }
  529. void App::OnPreMainMessageLoopRun() {
  530. content::BrowserChildProcessObserver::Add(this);
  531. if (process_singleton_) {
  532. process_singleton_->OnBrowserReady();
  533. }
  534. }
  535. void App::OnAccessibilitySupportChanged() {
  536. Emit("accessibility-support-changed", IsAccessibilitySupportEnabled());
  537. }
  538. #if defined(OS_MACOSX)
  539. void App::OnWillContinueUserActivity(bool* prevent_default,
  540. const std::string& type) {
  541. if (Emit("will-continue-activity", type)) {
  542. *prevent_default = true;
  543. }
  544. }
  545. void App::OnDidFailToContinueUserActivity(const std::string& type,
  546. const std::string& error) {
  547. Emit("continue-activity-error", type, error);
  548. }
  549. void App::OnContinueUserActivity(bool* prevent_default,
  550. const std::string& type,
  551. const base::DictionaryValue& user_info) {
  552. if (Emit("continue-activity", type, user_info)) {
  553. *prevent_default = true;
  554. }
  555. }
  556. void App::OnUserActivityWasContinued(const std::string& type,
  557. const base::DictionaryValue& user_info) {
  558. Emit("activity-was-continued", type, user_info);
  559. }
  560. void App::OnUpdateUserActivityState(bool* prevent_default,
  561. const std::string& type,
  562. const base::DictionaryValue& user_info) {
  563. if (Emit("update-activity-state", type, user_info)) {
  564. *prevent_default = true;
  565. }
  566. }
  567. void App::OnNewWindowForTab() {
  568. Emit("new-window-for-tab");
  569. }
  570. #endif
  571. bool App::CanCreateWindow(
  572. content::RenderFrameHost* opener,
  573. const GURL& opener_url,
  574. const GURL& opener_top_level_frame_url,
  575. const url::Origin& source_origin,
  576. content::mojom::WindowContainerType container_type,
  577. const GURL& target_url,
  578. const content::Referrer& referrer,
  579. const std::string& frame_name,
  580. WindowOpenDisposition disposition,
  581. const blink::mojom::WindowFeatures& features,
  582. const std::vector<std::string>& additional_features,
  583. const scoped_refptr<network::ResourceRequestBody>& body,
  584. bool user_gesture,
  585. bool opener_suppressed,
  586. bool* no_javascript_access) {
  587. v8::Locker locker(isolate());
  588. v8::HandleScope handle_scope(isolate());
  589. content::WebContents* web_contents =
  590. content::WebContents::FromRenderFrameHost(opener);
  591. if (web_contents) {
  592. auto api_web_contents = WebContents::From(isolate(), web_contents);
  593. // No need to emit any event if the WebContents is not available in JS.
  594. if (!api_web_contents.IsEmpty()) {
  595. api_web_contents->OnCreateWindow(target_url, referrer, frame_name,
  596. disposition, additional_features, body);
  597. }
  598. }
  599. return false;
  600. }
  601. void App::AllowCertificateError(
  602. content::WebContents* web_contents,
  603. int cert_error,
  604. const net::SSLInfo& ssl_info,
  605. const GURL& request_url,
  606. bool is_main_frame_request,
  607. bool strict_enforcement,
  608. const base::RepeatingCallback<void(content::CertificateRequestResultType)>&
  609. callback) {
  610. v8::Locker locker(isolate());
  611. v8::HandleScope handle_scope(isolate());
  612. bool prevent_default = Emit(
  613. "certificate-error", WebContents::FromOrCreate(isolate(), web_contents),
  614. request_url, net::ErrorToString(cert_error), ssl_info.cert, callback);
  615. // Deny the certificate by default.
  616. if (!prevent_default)
  617. callback.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
  618. }
  619. base::OnceClosure App::SelectClientCertificate(
  620. content::WebContents* web_contents,
  621. net::SSLCertRequestInfo* cert_request_info,
  622. net::ClientCertIdentityList identities,
  623. std::unique_ptr<content::ClientCertificateDelegate> delegate) {
  624. std::shared_ptr<content::ClientCertificateDelegate> shared_delegate(
  625. delegate.release());
  626. // Convert the ClientCertIdentityList to a CertificateList
  627. // to avoid changes in the API.
  628. auto client_certs = net::CertificateList();
  629. for (const std::unique_ptr<net::ClientCertIdentity>& identity : identities)
  630. client_certs.push_back(identity->certificate());
  631. auto shared_identities =
  632. std::make_shared<net::ClientCertIdentityList>(std::move(identities));
  633. bool prevent_default =
  634. Emit("select-client-certificate",
  635. WebContents::FromOrCreate(isolate(), web_contents),
  636. cert_request_info->host_and_port.ToString(), std::move(client_certs),
  637. base::BindOnce(&OnClientCertificateSelected, isolate(),
  638. shared_delegate, shared_identities));
  639. // Default to first certificate from the platform store.
  640. if (!prevent_default) {
  641. scoped_refptr<net::X509Certificate> cert =
  642. (*shared_identities)[0]->certificate();
  643. net::ClientCertIdentity::SelfOwningAcquirePrivateKey(
  644. std::move((*shared_identities)[0]),
  645. base::BindRepeating(&GotPrivateKey, shared_delegate, std::move(cert)));
  646. }
  647. return base::OnceClosure();
  648. }
  649. void App::OnGpuInfoUpdate() {
  650. Emit("gpu-info-update");
  651. }
  652. void App::OnGpuProcessCrashed(base::TerminationStatus status) {
  653. Emit("gpu-process-crashed",
  654. status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
  655. }
  656. void App::BrowserChildProcessLaunchedAndConnected(
  657. const content::ChildProcessData& data) {
  658. ChildProcessLaunched(data.process_type, data.GetProcess().Handle());
  659. }
  660. void App::BrowserChildProcessHostDisconnected(
  661. const content::ChildProcessData& data) {
  662. ChildProcessDisconnected(base::GetProcId(data.GetProcess().Handle()));
  663. }
  664. void App::BrowserChildProcessCrashed(
  665. const content::ChildProcessData& data,
  666. const content::ChildProcessTerminationInfo& info) {
  667. ChildProcessDisconnected(base::GetProcId(data.GetProcess().Handle()));
  668. }
  669. void App::BrowserChildProcessKilled(
  670. const content::ChildProcessData& data,
  671. const content::ChildProcessTerminationInfo& info) {
  672. ChildProcessDisconnected(base::GetProcId(data.GetProcess().Handle()));
  673. }
  674. void App::RenderProcessReady(content::RenderProcessHost* host) {
  675. ChildProcessLaunched(content::PROCESS_TYPE_RENDERER,
  676. host->GetProcess().Handle());
  677. // TODO(jeremy): this isn't really the right place to be creating
  678. // `WebContents` instances, but this was implicitly happening before in
  679. // `RenderProcessPreferences`, so this is at least more explicit...
  680. content::WebContents* web_contents =
  681. AtomBrowserClient::Get()->GetWebContentsFromProcessID(host->GetID());
  682. if (web_contents)
  683. WebContents::FromOrCreate(v8::Isolate::GetCurrent(), web_contents);
  684. }
  685. void App::RenderProcessDisconnected(base::ProcessId host_pid) {
  686. ChildProcessDisconnected(host_pid);
  687. }
  688. void App::ChildProcessLaunched(int process_type, base::ProcessHandle handle) {
  689. auto pid = base::GetProcId(handle);
  690. #if defined(OS_MACOSX)
  691. auto metrics = base::ProcessMetrics::CreateProcessMetrics(
  692. handle, content::BrowserChildProcessHost::GetPortProvider());
  693. #else
  694. auto metrics = base::ProcessMetrics::CreateProcessMetrics(handle);
  695. #endif
  696. app_metrics_[pid] = std::make_unique<electron::ProcessMetric>(
  697. process_type, handle, std::move(metrics));
  698. }
  699. void App::ChildProcessDisconnected(base::ProcessId pid) {
  700. app_metrics_.erase(pid);
  701. }
  702. base::FilePath App::GetAppPath() const {
  703. return app_path_;
  704. }
  705. void App::SetAppPath(const base::FilePath& app_path) {
  706. app_path_ = app_path;
  707. }
  708. #if !defined(OS_MACOSX)
  709. void App::SetAppLogsPath(base::Optional<base::FilePath> custom_path,
  710. mate::Arguments* args) {
  711. if (custom_path.has_value()) {
  712. if (!custom_path->IsAbsolute()) {
  713. args->ThrowError("Path must be absolute");
  714. return;
  715. }
  716. base::PathService::Override(DIR_APP_LOGS, custom_path.value());
  717. } else {
  718. base::FilePath path;
  719. if (base::PathService::Get(DIR_USER_DATA, &path)) {
  720. path = path.Append(base::FilePath::FromUTF8Unsafe(GetApplicationName()));
  721. path = path.Append(base::FilePath::FromUTF8Unsafe("logs"));
  722. base::PathService::Override(DIR_APP_LOGS, path);
  723. }
  724. }
  725. }
  726. #endif
  727. base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) {
  728. bool succeed = false;
  729. base::FilePath path;
  730. int key = GetPathConstant(name);
  731. if (key >= 0) {
  732. succeed = base::PathService::Get(key, &path);
  733. // If users try to get the logs path before setting a logs path,
  734. // set the path to a sensible default and then try to get it again
  735. if (!succeed && name == "logs") {
  736. base::ThreadRestrictions::ScopedAllowIO allow_io;
  737. SetAppLogsPath(base::Optional<base::FilePath>(), args);
  738. succeed = base::PathService::Get(key, &path);
  739. }
  740. }
  741. if (!succeed)
  742. args->ThrowError("Failed to get '" + name + "' path");
  743. return path;
  744. }
  745. void App::SetPath(mate::Arguments* args,
  746. const std::string& name,
  747. const base::FilePath& path) {
  748. if (!path.IsAbsolute()) {
  749. args->ThrowError("Path must be absolute");
  750. return;
  751. }
  752. bool succeed = false;
  753. int key = GetPathConstant(name);
  754. if (key >= 0)
  755. succeed =
  756. base::PathService::OverrideAndCreateIfNeeded(key, path, true, false);
  757. if (!succeed)
  758. args->ThrowError("Failed to set path");
  759. }
  760. void App::SetDesktopName(const std::string& desktop_name) {
  761. #if defined(OS_LINUX)
  762. std::unique_ptr<base::Environment> env(base::Environment::Create());
  763. env->SetVar("CHROME_DESKTOP", desktop_name);
  764. #endif
  765. }
  766. std::string App::GetLocale() {
  767. return g_browser_process->GetApplicationLocale();
  768. }
  769. std::string App::GetLocaleCountryCode() {
  770. std::string region;
  771. #if defined(OS_WIN)
  772. WCHAR locale_name[LOCALE_NAME_MAX_LENGTH] = {0};
  773. if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SISO3166CTRYNAME,
  774. (LPWSTR)&locale_name,
  775. sizeof(locale_name) / sizeof(WCHAR)) ||
  776. GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SISO3166CTRYNAME,
  777. (LPWSTR)&locale_name,
  778. sizeof(locale_name) / sizeof(WCHAR))) {
  779. base::WideToUTF8(locale_name, wcslen(locale_name), &region);
  780. }
  781. #elif defined(OS_MACOSX)
  782. CFLocaleRef locale = CFLocaleCopyCurrent();
  783. CFStringRef value = CFStringRef(
  784. static_cast<CFTypeRef>(CFLocaleGetValue(locale, kCFLocaleCountryCode)));
  785. const CFIndex kCStringSize = 128;
  786. char temporaryCString[kCStringSize] = {0};
  787. CFStringGetCString(value, temporaryCString, kCStringSize,
  788. kCFStringEncodingUTF8);
  789. region = temporaryCString;
  790. #else
  791. const char* locale_ptr = setlocale(LC_TIME, NULL);
  792. if (!locale_ptr)
  793. locale_ptr = setlocale(LC_NUMERIC, NULL);
  794. if (locale_ptr) {
  795. std::string locale = locale_ptr;
  796. std::string::size_type rpos = locale.find('.');
  797. if (rpos != std::string::npos)
  798. locale = locale.substr(0, rpos);
  799. rpos = locale.find('_');
  800. if (rpos != std::string::npos && rpos + 1 < locale.size())
  801. region = locale.substr(rpos + 1);
  802. }
  803. #endif
  804. return region.size() == 2 ? region : std::string();
  805. }
  806. void App::OnSecondInstance(const base::CommandLine::StringVector& cmd,
  807. const base::FilePath& cwd) {
  808. Emit("second-instance", cmd, cwd);
  809. }
  810. bool App::HasSingleInstanceLock() const {
  811. if (process_singleton_)
  812. return true;
  813. return false;
  814. }
  815. bool App::RequestSingleInstanceLock() {
  816. if (HasSingleInstanceLock())
  817. return true;
  818. base::FilePath user_dir;
  819. base::PathService::Get(DIR_USER_DATA, &user_dir);
  820. auto cb = base::BindRepeating(&App::OnSecondInstance, base::Unretained(this));
  821. process_singleton_.reset(new ProcessSingleton(
  822. user_dir, base::BindRepeating(NotificationCallbackWrapper, cb)));
  823. switch (process_singleton_->NotifyOtherProcessOrCreate()) {
  824. case ProcessSingleton::NotifyResult::LOCK_ERROR:
  825. case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
  826. case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED: {
  827. process_singleton_.reset();
  828. return false;
  829. }
  830. case ProcessSingleton::NotifyResult::PROCESS_NONE:
  831. default: // Shouldn't be needed, but VS warns if it is not there.
  832. return true;
  833. }
  834. }
  835. void App::ReleaseSingleInstanceLock() {
  836. if (process_singleton_) {
  837. process_singleton_->Cleanup();
  838. process_singleton_.reset();
  839. }
  840. }
  841. bool App::Relaunch(mate::Arguments* js_args) {
  842. // Parse parameters.
  843. bool override_argv = false;
  844. base::FilePath exec_path;
  845. relauncher::StringVector args;
  846. mate::Dictionary options;
  847. if (js_args->GetNext(&options)) {
  848. if (options.Get("execPath", &exec_path) | options.Get("args", &args))
  849. override_argv = true;
  850. }
  851. if (!override_argv) {
  852. const relauncher::StringVector& argv = electron::AtomCommandLine::argv();
  853. return relauncher::RelaunchApp(argv);
  854. }
  855. relauncher::StringVector argv;
  856. argv.reserve(1 + args.size());
  857. if (exec_path.empty()) {
  858. base::FilePath current_exe_path;
  859. base::PathService::Get(base::FILE_EXE, &current_exe_path);
  860. argv.push_back(current_exe_path.value());
  861. } else {
  862. argv.push_back(exec_path.value());
  863. }
  864. argv.insert(argv.end(), args.begin(), args.end());
  865. return relauncher::RelaunchApp(argv);
  866. }
  867. void App::DisableHardwareAcceleration(mate::Arguments* args) {
  868. if (Browser::Get()->is_ready()) {
  869. args->ThrowError(
  870. "app.disableHardwareAcceleration() can only be called "
  871. "before app is ready");
  872. return;
  873. }
  874. content::GpuDataManager::GetInstance()->DisableHardwareAcceleration();
  875. }
  876. void App::DisableDomainBlockingFor3DAPIs(mate::Arguments* args) {
  877. if (Browser::Get()->is_ready()) {
  878. args->ThrowError(
  879. "app.disableDomainBlockingFor3DAPIs() can only be called "
  880. "before app is ready");
  881. return;
  882. }
  883. content::GpuDataManagerImpl::GetInstance()
  884. ->DisableDomainBlockingFor3DAPIsForTesting();
  885. }
  886. bool App::IsAccessibilitySupportEnabled() {
  887. auto* ax_state = content::BrowserAccessibilityState::GetInstance();
  888. return ax_state->IsAccessibleBrowser();
  889. }
  890. void App::SetAccessibilitySupportEnabled(bool enabled, mate::Arguments* args) {
  891. if (!Browser::Get()->is_ready()) {
  892. args->ThrowError(
  893. "app.setAccessibilitySupportEnabled() can only be called "
  894. "after app is ready");
  895. return;
  896. }
  897. auto* ax_state = content::BrowserAccessibilityState::GetInstance();
  898. if (enabled) {
  899. ax_state->OnScreenReaderDetected();
  900. } else {
  901. ax_state->DisableAccessibility();
  902. }
  903. Browser::Get()->OnAccessibilitySupportChanged();
  904. }
  905. Browser::LoginItemSettings App::GetLoginItemSettings(mate::Arguments* args) {
  906. Browser::LoginItemSettings options;
  907. args->GetNext(&options);
  908. return Browser::Get()->GetLoginItemSettings(options);
  909. }
  910. #if defined(USE_NSS_CERTS)
  911. void App::ImportCertificate(const base::DictionaryValue& options,
  912. net::CompletionRepeatingCallback callback) {
  913. auto browser_context = AtomBrowserContext::From("", false);
  914. if (!certificate_manager_model_) {
  915. auto copy = base::DictionaryValue::From(
  916. base::Value::ToUniquePtrValue(options.Clone()));
  917. CertificateManagerModel::Create(
  918. browser_context.get(),
  919. base::BindRepeating(&App::OnCertificateManagerModelCreated,
  920. base::Unretained(this), base::Passed(&copy),
  921. callback));
  922. return;
  923. }
  924. int rv = ImportIntoCertStore(certificate_manager_model_.get(), options);
  925. std::move(callback).Run(rv);
  926. }
  927. void App::OnCertificateManagerModelCreated(
  928. std::unique_ptr<base::DictionaryValue> options,
  929. net::CompletionOnceCallback callback,
  930. std::unique_ptr<CertificateManagerModel> model) {
  931. certificate_manager_model_ = std::move(model);
  932. int rv =
  933. ImportIntoCertStore(certificate_manager_model_.get(), *(options.get()));
  934. std::move(callback).Run(rv);
  935. }
  936. #endif
  937. #if defined(OS_WIN)
  938. v8::Local<v8::Value> App::GetJumpListSettings() {
  939. JumpList jump_list(Browser::Get()->GetAppUserModelID());
  940. int min_items = 10;
  941. std::vector<JumpListItem> removed_items;
  942. if (jump_list.Begin(&min_items, &removed_items)) {
  943. // We don't actually want to change anything, so abort the transaction.
  944. jump_list.Abort();
  945. } else {
  946. LOG(ERROR) << "Failed to begin Jump List transaction.";
  947. }
  948. auto dict = mate::Dictionary::CreateEmpty(isolate());
  949. dict.Set("minItems", min_items);
  950. dict.Set("removedItems", mate::ConvertToV8(isolate(), removed_items));
  951. return dict.GetHandle();
  952. }
  953. JumpListResult App::SetJumpList(v8::Local<v8::Value> val,
  954. mate::Arguments* args) {
  955. std::vector<JumpListCategory> categories;
  956. bool delete_jump_list = val->IsNull();
  957. if (!delete_jump_list &&
  958. !mate::ConvertFromV8(args->isolate(), val, &categories)) {
  959. args->ThrowError("Argument must be null or an array of categories");
  960. return JumpListResult::ARGUMENT_ERROR;
  961. }
  962. JumpList jump_list(Browser::Get()->GetAppUserModelID());
  963. if (delete_jump_list) {
  964. return jump_list.Delete() ? JumpListResult::SUCCESS
  965. : JumpListResult::GENERIC_ERROR;
  966. }
  967. // Start a transaction that updates the JumpList of this application.
  968. if (!jump_list.Begin())
  969. return JumpListResult::GENERIC_ERROR;
  970. JumpListResult result = jump_list.AppendCategories(categories);
  971. // AppendCategories may have failed to add some categories, but it's better
  972. // to have something than nothing so try to commit the changes anyway.
  973. if (!jump_list.Commit()) {
  974. LOG(ERROR) << "Failed to commit changes to custom Jump List.";
  975. // It's more useful to return the earlier error code that might give
  976. // some indication as to why the transaction actually failed, so don't
  977. // overwrite it with a "generic error" code here.
  978. if (result == JumpListResult::SUCCESS)
  979. result = JumpListResult::GENERIC_ERROR;
  980. }
  981. return result;
  982. }
  983. #endif // defined(OS_WIN)
  984. v8::Local<v8::Promise> App::GetFileIcon(const base::FilePath& path,
  985. mate::Arguments* args) {
  986. util::Promise promise(isolate());
  987. v8::Local<v8::Promise> handle = promise.GetHandle();
  988. base::FilePath normalized_path = path.NormalizePathSeparators();
  989. IconLoader::IconSize icon_size;
  990. mate::Dictionary options;
  991. if (!args->GetNext(&options)) {
  992. icon_size = IconLoader::IconSize::NORMAL;
  993. } else {
  994. std::string icon_size_string;
  995. options.Get("size", &icon_size_string);
  996. icon_size = GetIconSizeByString(icon_size_string);
  997. }
  998. auto* icon_manager = AtomBrowserMainParts::Get()->GetIconManager();
  999. gfx::Image* icon =
  1000. icon_manager->LookupIconFromFilepath(normalized_path, icon_size);
  1001. if (icon) {
  1002. promise.Resolve(*icon);
  1003. } else {
  1004. icon_manager->LoadIcon(
  1005. normalized_path, icon_size,
  1006. base::BindOnce(&OnIconDataAvailable, std::move(promise)),
  1007. &cancelable_task_tracker_);
  1008. }
  1009. return handle;
  1010. }
  1011. std::vector<mate::Dictionary> App::GetAppMetrics(v8::Isolate* isolate) {
  1012. std::vector<mate::Dictionary> result;
  1013. result.reserve(app_metrics_.size());
  1014. int processor_count = base::SysInfo::NumberOfProcessors();
  1015. for (const auto& process_metric : app_metrics_) {
  1016. mate::Dictionary pid_dict = mate::Dictionary::CreateEmpty(isolate);
  1017. mate::Dictionary cpu_dict = mate::Dictionary::CreateEmpty(isolate);
  1018. pid_dict.SetHidden("simple", true);
  1019. cpu_dict.SetHidden("simple", true);
  1020. cpu_dict.Set(
  1021. "percentCPUUsage",
  1022. process_metric.second->metrics->GetPlatformIndependentCPUUsage() /
  1023. processor_count);
  1024. #if !defined(OS_WIN)
  1025. cpu_dict.Set("idleWakeupsPerSecond",
  1026. process_metric.second->metrics->GetIdleWakeupsPerSecond());
  1027. #else
  1028. // Chrome's underlying process_metrics.cc will throw a non-fatal warning
  1029. // that this method isn't implemented on Windows, so set it to 0 instead
  1030. // of calling it
  1031. cpu_dict.Set("idleWakeupsPerSecond", 0);
  1032. #endif
  1033. pid_dict.Set("cpu", cpu_dict);
  1034. pid_dict.Set("pid", process_metric.second->process.Pid());
  1035. pid_dict.Set("type", content::GetProcessTypeNameInEnglish(
  1036. process_metric.second->type));
  1037. pid_dict.Set("creationTime",
  1038. process_metric.second->process.CreationTime().ToJsTime());
  1039. #if !defined(OS_LINUX)
  1040. auto memory_info = process_metric.second->GetMemoryInfo();
  1041. mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate);
  1042. memory_dict.SetHidden("simple", true);
  1043. memory_dict.Set("workingSetSize",
  1044. static_cast<double>(memory_info.working_set_size >> 10));
  1045. memory_dict.Set(
  1046. "peakWorkingSetSize",
  1047. static_cast<double>(memory_info.peak_working_set_size >> 10));
  1048. #if defined(OS_WIN)
  1049. memory_dict.Set("privateBytes",
  1050. static_cast<double>(memory_info.private_bytes >> 10));
  1051. #endif
  1052. pid_dict.Set("memory", memory_dict);
  1053. #endif
  1054. #if defined(OS_MACOSX)
  1055. pid_dict.Set("sandboxed", process_metric.second->IsSandboxed());
  1056. #elif defined(OS_WIN)
  1057. auto integrity_level = process_metric.second->GetIntegrityLevel();
  1058. auto sandboxed = ProcessMetric::IsSandboxed(integrity_level);
  1059. pid_dict.Set("integrityLevel", integrity_level);
  1060. pid_dict.Set("sandboxed", sandboxed);
  1061. #endif
  1062. result.push_back(pid_dict);
  1063. }
  1064. return result;
  1065. }
  1066. v8::Local<v8::Value> App::GetGPUFeatureStatus(v8::Isolate* isolate) {
  1067. auto status = content::GetFeatureStatus();
  1068. base::DictionaryValue temp;
  1069. return mate::ConvertToV8(isolate, status ? *status : temp);
  1070. }
  1071. v8::Local<v8::Promise> App::GetGPUInfo(v8::Isolate* isolate,
  1072. const std::string& info_type) {
  1073. auto* const gpu_data_manager = content::GpuDataManagerImpl::GetInstance();
  1074. util::Promise promise(isolate);
  1075. v8::Local<v8::Promise> handle = promise.GetHandle();
  1076. if (info_type != "basic" && info_type != "complete") {
  1077. promise.RejectWithErrorMessage(
  1078. "Invalid info type. Use 'basic' or 'complete'");
  1079. return handle;
  1080. }
  1081. std::string reason;
  1082. if (!gpu_data_manager->GpuAccessAllowed(&reason)) {
  1083. promise.RejectWithErrorMessage("GPU access not allowed. Reason: " + reason);
  1084. return handle;
  1085. }
  1086. auto* const info_mgr = GPUInfoManager::GetInstance();
  1087. if (info_type == "complete") {
  1088. #if defined(OS_WIN) || defined(OS_MACOSX)
  1089. info_mgr->FetchCompleteInfo(std::move(promise));
  1090. #else
  1091. info_mgr->FetchBasicInfo(std::move(promise));
  1092. #endif
  1093. } else /* (info_type == "basic") */ {
  1094. info_mgr->FetchBasicInfo(std::move(promise));
  1095. }
  1096. return handle;
  1097. }
  1098. static void RemoveNoSandboxSwitch(base::CommandLine* command_line) {
  1099. if (command_line->HasSwitch(service_manager::switches::kNoSandbox)) {
  1100. const base::CommandLine::CharType* noSandboxArg =
  1101. FILE_PATH_LITERAL("--no-sandbox");
  1102. base::CommandLine::StringVector modified_command_line;
  1103. for (auto& arg : command_line->argv()) {
  1104. if (arg.compare(noSandboxArg) != 0) {
  1105. modified_command_line.push_back(arg);
  1106. }
  1107. }
  1108. command_line->InitFromArgv(modified_command_line);
  1109. }
  1110. }
  1111. void App::EnableSandbox(mate::Arguments* args) {
  1112. if (Browser::Get()->is_ready()) {
  1113. args->ThrowError(
  1114. "app.enableSandbox() can only be called "
  1115. "before app is ready");
  1116. return;
  1117. }
  1118. auto* command_line = base::CommandLine::ForCurrentProcess();
  1119. RemoveNoSandboxSwitch(command_line);
  1120. command_line->AppendSwitch(switches::kEnableSandbox);
  1121. }
  1122. void App::SetUserAgentFallback(const std::string& user_agent) {
  1123. AtomBrowserClient::Get()->SetUserAgent(user_agent);
  1124. }
  1125. std::string App::GetUserAgentFallback() {
  1126. return AtomBrowserClient::Get()->GetUserAgent();
  1127. }
  1128. void App::SetBrowserClientCanUseCustomSiteInstance(bool should_disable) {
  1129. AtomBrowserClient::Get()->SetCanUseCustomSiteInstance(should_disable);
  1130. }
  1131. bool App::CanBrowserClientUseCustomSiteInstance() {
  1132. return AtomBrowserClient::Get()->CanUseCustomSiteInstance();
  1133. }
  1134. #if defined(OS_MACOSX)
  1135. bool App::MoveToApplicationsFolder(mate::Arguments* args) {
  1136. return ui::cocoa::AtomBundleMover::Move(args);
  1137. }
  1138. bool App::IsInApplicationsFolder() {
  1139. return ui::cocoa::AtomBundleMover::IsCurrentAppInApplicationsFolder();
  1140. }
  1141. int DockBounce(mate::Arguments* args) {
  1142. int request_id = -1;
  1143. std::string type = "informational";
  1144. args->GetNext(&type);
  1145. if (type == "critical")
  1146. request_id = Browser::Get()->DockBounce(Browser::BounceType::CRITICAL);
  1147. else if (type == "informational")
  1148. request_id = Browser::Get()->DockBounce(Browser::BounceType::INFORMATIONAL);
  1149. return request_id;
  1150. }
  1151. void DockSetMenu(electron::api::Menu* menu) {
  1152. Browser::Get()->DockSetMenu(menu->model());
  1153. }
  1154. v8::Local<v8::Value> App::GetDockAPI(v8::Isolate* isolate) {
  1155. if (dock_.IsEmpty()) {
  1156. // Initialize the Dock API, the methods are bound to "dock" which exists
  1157. // for the lifetime of "app"
  1158. auto browser = base::Unretained(Browser::Get());
  1159. mate::Dictionary dock_obj = mate::Dictionary::CreateEmpty(isolate);
  1160. dock_obj.SetMethod("bounce", &DockBounce);
  1161. dock_obj.SetMethod(
  1162. "cancelBounce",
  1163. base::BindRepeating(&Browser::DockCancelBounce, browser));
  1164. dock_obj.SetMethod(
  1165. "downloadFinished",
  1166. base::BindRepeating(&Browser::DockDownloadFinished, browser));
  1167. dock_obj.SetMethod(
  1168. "setBadge", base::BindRepeating(&Browser::DockSetBadgeText, browser));
  1169. dock_obj.SetMethod(
  1170. "getBadge", base::BindRepeating(&Browser::DockGetBadgeText, browser));
  1171. dock_obj.SetMethod("hide",
  1172. base::BindRepeating(&Browser::DockHide, browser));
  1173. dock_obj.SetMethod("show",
  1174. base::BindRepeating(&Browser::DockShow, browser));
  1175. dock_obj.SetMethod("isVisible",
  1176. base::BindRepeating(&Browser::DockIsVisible, browser));
  1177. dock_obj.SetMethod("setMenu", &DockSetMenu);
  1178. dock_obj.SetMethod("setIcon",
  1179. base::BindRepeating(&Browser::DockSetIcon, browser));
  1180. dock_.Reset(isolate, dock_obj.GetHandle());
  1181. }
  1182. return v8::Local<v8::Value>::New(isolate, dock_);
  1183. }
  1184. #endif
  1185. // static
  1186. mate::Handle<App> App::Create(v8::Isolate* isolate) {
  1187. return mate::CreateHandle(isolate, new App(isolate));
  1188. }
  1189. // static
  1190. void App::BuildPrototype(v8::Isolate* isolate,
  1191. v8::Local<v8::FunctionTemplate> prototype) {
  1192. prototype->SetClassName(mate::StringToV8(isolate, "App"));
  1193. auto browser = base::Unretained(Browser::Get());
  1194. mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
  1195. .SetMethod("quit", base::BindRepeating(&Browser::Quit, browser))
  1196. .SetMethod("exit", base::BindRepeating(&Browser::Exit, browser))
  1197. .SetMethod("focus", base::BindRepeating(&Browser::Focus, browser))
  1198. .SetMethod("getVersion",
  1199. base::BindRepeating(&Browser::GetVersion, browser))
  1200. .SetMethod("setVersion",
  1201. base::BindRepeating(&Browser::SetVersion, browser))
  1202. .SetMethod("_getName", base::BindRepeating(&Browser::GetName, browser))
  1203. .SetMethod("_setName", base::BindRepeating(&Browser::SetName, browser))
  1204. .SetMethod("isReady", base::BindRepeating(&Browser::is_ready, browser))
  1205. .SetMethod("whenReady", base::BindRepeating(&Browser::WhenReady, browser))
  1206. .SetMethod("addRecentDocument",
  1207. base::BindRepeating(&Browser::AddRecentDocument, browser))
  1208. .SetMethod("clearRecentDocuments",
  1209. base::BindRepeating(&Browser::ClearRecentDocuments, browser))
  1210. .SetMethod("setAppUserModelId",
  1211. base::BindRepeating(&Browser::SetAppUserModelID, browser))
  1212. .SetMethod(
  1213. "isDefaultProtocolClient",
  1214. base::BindRepeating(&Browser::IsDefaultProtocolClient, browser))
  1215. .SetMethod(
  1216. "setAsDefaultProtocolClient",
  1217. base::BindRepeating(&Browser::SetAsDefaultProtocolClient, browser))
  1218. .SetMethod(
  1219. "removeAsDefaultProtocolClient",
  1220. base::BindRepeating(&Browser::RemoveAsDefaultProtocolClient, browser))
  1221. .SetMethod("_setBadgeCount",
  1222. base::BindRepeating(&Browser::SetBadgeCount, browser))
  1223. .SetMethod("_getBadgeCount",
  1224. base::BindRepeating(&Browser::GetBadgeCount, browser))
  1225. .SetMethod("getLoginItemSettings", &App::GetLoginItemSettings)
  1226. .SetMethod("setLoginItemSettings",
  1227. base::BindRepeating(&Browser::SetLoginItemSettings, browser))
  1228. .SetMethod("isEmojiPanelSupported",
  1229. base::BindRepeating(&Browser::IsEmojiPanelSupported, browser))
  1230. .SetProperty("badgeCount",
  1231. base::BindRepeating(&Browser::GetBadgeCount, browser),
  1232. base::BindRepeating(&Browser::SetBadgeCount, browser))
  1233. .SetProperty("name", base::BindRepeating(&Browser::GetName, browser),
  1234. base::BindRepeating(&Browser::SetName, browser))
  1235. #if defined(OS_MACOSX)
  1236. .SetMethod("hide", base::BindRepeating(&Browser::Hide, browser))
  1237. .SetMethod("show", base::BindRepeating(&Browser::Show, browser))
  1238. .SetMethod("setUserActivity",
  1239. base::BindRepeating(&Browser::SetUserActivity, browser))
  1240. .SetMethod("getCurrentActivityType",
  1241. base::BindRepeating(&Browser::GetCurrentActivityType, browser))
  1242. .SetMethod(
  1243. "invalidateCurrentActivity",
  1244. base::BindRepeating(&Browser::InvalidateCurrentActivity, browser))
  1245. .SetMethod("resignCurrentActivity",
  1246. base::BindRepeating(&Browser::ResignCurrentActivity, browser))
  1247. .SetMethod("updateCurrentActivity",
  1248. base::BindRepeating(&Browser::UpdateCurrentActivity, browser))
  1249. .SetMethod("moveToApplicationsFolder", &App::MoveToApplicationsFolder)
  1250. .SetMethod("isInApplicationsFolder", &App::IsInApplicationsFolder)
  1251. #endif
  1252. #if defined(OS_MACOSX) || defined(OS_LINUX)
  1253. .SetMethod("setAboutPanelOptions",
  1254. base::BindRepeating(&Browser::SetAboutPanelOptions, browser))
  1255. .SetMethod("showAboutPanel",
  1256. base::BindRepeating(&Browser::ShowAboutPanel, browser))
  1257. #endif
  1258. #if defined(OS_MACOSX) || defined(OS_WIN)
  1259. .SetMethod("showEmojiPanel",
  1260. base::BindRepeating(&Browser::ShowEmojiPanel, browser))
  1261. .SetProperty("accessibilitySupportEnabled",
  1262. &App::IsAccessibilitySupportEnabled,
  1263. &App::SetAccessibilitySupportEnabled)
  1264. #endif
  1265. #if defined(OS_WIN)
  1266. .SetMethod("setUserTasks",
  1267. base::BindRepeating(&Browser::SetUserTasks, browser))
  1268. .SetMethod("getJumpListSettings", &App::GetJumpListSettings)
  1269. .SetMethod("setJumpList", &App::SetJumpList)
  1270. #endif
  1271. #if defined(OS_LINUX)
  1272. .SetMethod("isUnityRunning",
  1273. base::BindRepeating(&Browser::IsUnityRunning, browser))
  1274. #endif
  1275. .SetMethod("setAppPath", &App::SetAppPath)
  1276. .SetMethod("getAppPath", &App::GetAppPath)
  1277. .SetMethod("setPath", &App::SetPath)
  1278. .SetMethod("getPath", &App::GetPath)
  1279. .SetMethod("setAppLogsPath", &App::SetAppLogsPath)
  1280. .SetMethod("setDesktopName", &App::SetDesktopName)
  1281. .SetMethod("getLocale", &App::GetLocale)
  1282. .SetMethod("getLocaleCountryCode", &App::GetLocaleCountryCode)
  1283. #if defined(USE_NSS_CERTS)
  1284. .SetMethod("importCertificate", &App::ImportCertificate)
  1285. #endif
  1286. .SetMethod("hasSingleInstanceLock", &App::HasSingleInstanceLock)
  1287. .SetMethod("requestSingleInstanceLock", &App::RequestSingleInstanceLock)
  1288. .SetMethod("releaseSingleInstanceLock", &App::ReleaseSingleInstanceLock)
  1289. .SetMethod("relaunch", &App::Relaunch)
  1290. .SetMethod("_isAccessibilitySupportEnabled",
  1291. &App::IsAccessibilitySupportEnabled)
  1292. .SetMethod("_setAccessibilitySupportEnabled",
  1293. &App::SetAccessibilitySupportEnabled)
  1294. .SetMethod("disableHardwareAcceleration",
  1295. &App::DisableHardwareAcceleration)
  1296. .SetMethod("disableDomainBlockingFor3DAPIs",
  1297. &App::DisableDomainBlockingFor3DAPIs)
  1298. .SetMethod("getFileIcon", &App::GetFileIcon)
  1299. .SetMethod("getAppMetrics", &App::GetAppMetrics)
  1300. .SetMethod("getGPUFeatureStatus", &App::GetGPUFeatureStatus)
  1301. .SetMethod("getGPUInfo", &App::GetGPUInfo)
  1302. #if defined(MAS_BUILD)
  1303. .SetMethod("startAccessingSecurityScopedResource",
  1304. &App::StartAccessingSecurityScopedResource)
  1305. #endif
  1306. #if defined(OS_MACOSX)
  1307. .SetProperty("dock", &App::GetDockAPI)
  1308. #endif
  1309. .SetProperty("userAgentFallback", &App::GetUserAgentFallback,
  1310. &App::SetUserAgentFallback)
  1311. .SetMethod("enableSandbox", &App::EnableSandbox)
  1312. .SetProperty("allowRendererProcessReuse",
  1313. &App::CanBrowserClientUseCustomSiteInstance,
  1314. &App::SetBrowserClientCanUseCustomSiteInstance);
  1315. }
  1316. } // namespace api
  1317. } // namespace electron
  1318. namespace {
  1319. void Initialize(v8::Local<v8::Object> exports,
  1320. v8::Local<v8::Value> unused,
  1321. v8::Local<v8::Context> context,
  1322. void* priv) {
  1323. v8::Isolate* isolate = context->GetIsolate();
  1324. mate::Dictionary dict(isolate, exports);
  1325. dict.Set("App", electron::api::App::GetConstructor(isolate)
  1326. ->GetFunction(context)
  1327. .ToLocalChecked());
  1328. dict.Set("app", electron::api::App::Create(isolate));
  1329. }
  1330. } // namespace
  1331. NODE_LINKED_MODULE_CONTEXT_AWARE(atom_browser_app, Initialize)