Browse Source

feat: expose system preferences to utility process (#42599)

* chore: expose  system preferences to utility process

* chore: add tests, doc changes and module-list update

* relative link

* use @

* fix test

* chore: disable linux test

* kick

* noop on windows utility process

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: George Xu <[email protected]>
trop[bot] 10 months ago
parent
commit
50ea20168d

+ 1 - 1
docs/api/system-preferences.md

@@ -2,7 +2,7 @@
 
 > Get system preferences.
 
-Process: [Main](../glossary.md#main-process)
+Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)
 
 ```js
 const { systemPreferences } = require('electron')

+ 1 - 0
filenames.auto.gni

@@ -350,6 +350,7 @@ auto_filenames = {
 
   utility_bundle_deps = [
     "lib/browser/api/net-fetch.ts",
+    "lib/browser/api/system-preferences.ts",
     "lib/browser/message-port-main.ts",
     "lib/common/api/net-client-request.ts",
     "lib/common/define-properties.ts",

+ 2 - 1
lib/utility/api/module-list.ts

@@ -1,4 +1,5 @@
 // Utility side modules, please sort alphabetically.
 export const utilityNodeModuleList: ElectronInternal.ModuleEntry[] = [
-  { name: 'net', loader: () => require('./net') }
+  { name: 'net', loader: () => require('./net') },
+  { name: 'systemPreferences', loader: () => require('@electron/internal/browser/api/system-preferences') }
 ];

+ 2 - 0
shell/browser/api/electron_api_system_preferences_win.cc

@@ -159,6 +159,8 @@ std::string SystemPreferences::GetMediaAccessStatus(
 }
 
 void SystemPreferences::InitializeWindow() {
+  if (electron::IsUtilityProcess())
+    return;
   // Wait until app is ready before creating sys color listener
   // Creating this listener before the app is ready causes global shortcuts
   // to not fire

+ 4 - 3
shell/common/node_bindings.cc

@@ -100,9 +100,10 @@
   V(electron_renderer_ipc)            \
   V(electron_renderer_web_frame)
 
-#define ELECTRON_UTILITY_BINDINGS(V) \
-  V(electron_browser_event_emitter)  \
-  V(electron_common_net)             \
+#define ELECTRON_UTILITY_BINDINGS(V)     \
+  V(electron_browser_event_emitter)      \
+  V(electron_browser_system_preferences) \
+  V(electron_common_net)                 \
   V(electron_utility_parent_port)
 
 #define ELECTRON_TESTING_BINDINGS(V) V(electron_common_testing)

+ 13 - 0
spec/api-utility-process-spec.ts

@@ -7,6 +7,7 @@ import { closeWindow } from './lib/window-helpers';
 import { once } from 'node:events';
 import { pathToFileURL } from 'node:url';
 import { setImmediate } from 'node:timers/promises';
+import { systemPreferences } from 'electron';
 
 const fixturesPath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process');
 const isWindowsOnArm = process.platform === 'win32' && process.arch === 'arm64';
@@ -404,6 +405,18 @@ describe('utilityProcess module', () => {
       expect(output).to.include(result);
     });
 
+    ifit(process.platform !== 'linux')('can access exposed main process modules from the utility process', async () => {
+      const message = 'Message from utility process';
+      const child = utilityProcess.fork(path.join(fixturesPath, 'expose-main-process-module.js'));
+      await once(child, 'spawn');
+      child.postMessage(message);
+      const [data] = await once(child, 'message');
+      expect(data).to.equal(systemPreferences.getMediaAccessStatus('screen'));
+      const exit = once(child, 'exit');
+      expect(child.kill()).to.be.true();
+      await exit;
+    });
+
     it('can establish communication channel with sandboxed renderer', async () => {
       const result = 'Message from sandboxed renderer';
       const w = new BrowserWindow({

+ 6 - 0
spec/fixtures/api/utility-process/expose-main-process-module.js

@@ -0,0 +1,6 @@
+const { systemPreferences } = require('electron');
+
+const status = systemPreferences.getMediaAccessStatus('screen');
+process.parentPort.on('message', () => {
+  process.parentPort.postMessage(status);
+});