Processes & Concurrency

RSS for tag

Discover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.

Concurrency Documentation

Posts under Processes & Concurrency subtopic

Post

Replies

Boosts

Views

Activity

Processes & Concurrency Resources
General: DevForums subtopic: App & System Services > Processes & Concurrency Processes & concurrency covers a number of different technologies: Background Tasks Resources Concurrency Resources — This includes Swift concurrency. Service Management Resources XPC Resources Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
1.6k
Jul ’25
Supported libSystem state after a LaunchDaemon permanently drops privileges
I am testing a fixed signed LaunchDaemon startup program that uses setgroups, setgid and setuid to establish a dedicated non-root identity before loading its service library or creating an application XPC listener. This follows the single-process, deferred-library direction discussed in DTS thread 844906. The remaining question is the supported treatment of system-runtime state initialized before the credential transition. Test environment: Apple silicon, macOS 27.0.1 / Darwin 27.0.0, hardened runtime, no special entitlements. The host links only libSystem and has no application constructors. This is a temporary diagnostic, not an installed product or a file-operation service. Our test verifies real, effective and saved UID/GID, the exact supplementary group vector and failed attempts to regain root. After the transition, a read-only own-task Mach inventory still sees a voucher even though successful task/current-thread voucher getters return null. It also sees one send+receive endpoint without an alias to any of the queried special/registered roles. Ordinary hardened launchd controls in both the login GUI and user domains also have a voucher and such an endpoint. Their recorded endpoint attributes match the post-drop test: empty queue, sequence 1, make-send count 1, send rights present, no send-once rights, port sets or notification requests. We do not treat this as proof that the objects or authority are equivalent. No messages are sent to the unidentified endpoint and no runtime-owned rights are destroyed. In a separate ordinary-user test, public voucher recipe extraction reports only a BANK attribute. Published libdispatch source describes a default task-bank voucher stored separately from the current thread's voucher slot. Published XNU source captures identity when bank context is initialized. We have not established the corresponding lifecycle or authority implications on this OS release, and do not claim that the observed voucher retains root authority. For this startup arrangement, what supported public contract should an application use to establish that libSystem's retained runtime context does not preserve usable pre-drop administrator authority before loading service code? Is there a supported sanitization step, or a specific documented OS trust assumption under which leaving that state intact is intended? If the combination of exact group reduction, deferred service loading and launchd Mach-service check-in cannot support that boundary, which public architecture should we use instead? We are seeking a documented arrangement or a clear limit on the guarantee, rather than a private reset API or an explanation of every internal endpoint. We have not used same-PID exec, a root supervisor, private APIs, or a broad port-type allowlist. Relevant documentation or a minimal public sample would help.
0
0
106
5h
Subprocess ownership and timeout recovery on Intel macOS Monterey
Hi Quinn, Following your recommendation by email, I’m posting this as a new thread. Thank you again for your guidance on Virtualization.framework. This is a separate question about ordinary host-side subprocess ownership and timeout recovery, not VM cleanup. Target environment: Intel x86_64 macOS Monterey 12.7.6, build 21H1320 Python 3.13.15 Public, supported mechanisms; no root privileges, private APIs or kernel extensions We are verifying a subprocess supervision component with this process structure: Trusted caller process → runner → pytest → private helper → native subprocess Each parent normally owns the consuming wait for its direct child. The private helper exclusively manages signalling and reaping of its native child. Outer processes do not signal saved helper/native PIDs. Cancellation is cooperative, through channels and file/token delivery. The runner observes its fresh pytest child, drains stdout/stderr with bounded retention, and consumes its exact child’s status after exit is observed. The runner, pytest and helper are launched in separate sessions. Consequently, signalling pytest’s process group would not cover the separately sessioned helper and its native child. The unresolved failure case is: A fresh pytest invocation starts. Cancellation delivery fails, or delivery succeeds but the work does not finish. The runner continues observation and bounded output draining within the remaining deadline. The deadline expires while pytest or processes below it may still be alive. The runner reports an unresolved outcome and may exit. The caller also has a bounded deadline and may return without consuming its runner child. Closing capture pipes can cause EPIPE and disturb the child’s cleanup. Exiting a consuming parent also relinquishes its ability to collect that child’s eventual status. The outer caller does not automatically acquire wait rights over pytest or its descendants. Our current policy retains affected files, preserves the original failure, and prevents subsequent tests from starting. We do not treat cancellation delivery, pipe EOF, successful signal delivery, or direct-child reap as proof that every descendant has stopped. This prevents false success, but does not resolve responsibility for work that remains alive. We have considered separating the caller’s response lifetime from the consuming owners’ lifetimes: the caller could return an unresolved response while both existing parents remain alive, draining output and collecting their direct children later. However, keeping them alive adds no termination authority and does not address a crash of either owner. I am not asking for an absolute guarantee against arbitrary kernel failures, or a promise that SIGKILL always completes within a fixed time. I would like to understand the supported architectural approach on Monterey. My questions are: Is retaining the existing consuming parents beyond the response deadline the appropriate pattern, or is there a supported macOS facility that provides a better ownership and recovery boundary? What safe termination authority should those owners retain over their fresh direct children? If process groups are part of the solution, what lifecycle rules are needed to avoid acting on a reused identifier, particularly after leader exit or reaping? Is there a supported way to manage the separately sessioned helper/native work if an intermediate parent exits? Or must each level independently retain its own supervision and cleanup responsibility? If the consuming owner itself crashes, is there a supported recovery mechanism for ordinary subprocesses? Would launchd or XPC materially help, and what limitations would remain for descendants in separate sessions? Which design constraint would you recommend changing: cooperative-only cancellation, the fixed lifetime of the runner, or the process topology? These are our current choices, not restrictions we assume macOS imposes. Our practical goal is a bounded response while an identifiable owner remains responsible for unsettled work, with appropriate termination authority and an honest unresolved outcome when cleanup cannot be established. The immediate qualification scope is only three simple tests, using shell bodies such as exit, kill -9 $$, and echo with ordinary exit statuses. They contain no intentional background work, pipelines or command substitutions. We would prefer a proportionate supported pattern rather than a new general supervision framework. If a reduced example would help clarify the question, I can provide one. Thank you for your time and guidance.
4
0
72
10h
macOS: supported process-tree lifetime boundary after supervisor loss
I am building Ouroboros (ouro-jail), a contained developer workload runner. Before advertising native macOS support, I need a supported lifetime boundary that covers ordinary fork/spawn/exec descendants, including detached sessions and double-fork daemons. Execution must stay contained when every userspace custodian dies, rather than relying on a surviving process to enumerate and kill descendants. Does macOS provide a supported facility that can: Establish an immutable workload scope before its first instruction and atomically inherit membership through fork/spawn/exec, without modifying the workload or preventing ordinary Node, shell and Git subprocess behavior? Stop or terminate every member after loss of the final control owner, with enforcement retained in the kernel and no userspace callback required? Handle concurrent creation during teardown and expose a verifiable final drain, using stable process identities rather than PID-only scans? Development evidence on macOS 27.0 build 26A428, XNU 13432.1.9 (isolated VM, SIP already disabled in the guest; this is development evidence, not normal-SIP qualification): Descendant-scoped Endpoint Security clients observe the tested subtree. Reciprocal custodians handle either client's loss, but killing both leaves all known members running. Uncached fail-closed AUTH_EXEC lets a survivor execute a new command after both clients disappear (200 reciprocal-custody trials). PT_ATTACHEXC gives kernel-enforced debugger-death cleanup for attached targets, but later fork/spawn children survive (80 debugger-lifetime trials). A locally installed, identity-protected Mach exception handler is inherited through the tested fork/spawn/exec paths. Owner death changes it to a dead handler without stopping normal execution; a child can clear it. Breakpoint controls confirm real kernel exception delivery (24 Mach-lifetime trials). Published XNU contains per-task fatal-port no-senders cleanup, but machdep.task_get_fatal_port is absent on this tested release kernel. I have not treated it as a supported application API. LaunchServices creates a real application coalition, and XPC service lifetime follows app death. However, all seven workload descendants survive, retain coalition membership and can execute a new command. Shared and private audit sessions both fail; eight-second follow-ups also retain all seven survivors. A temporary root launchd service restarts and reaps seven recorded processes after a crash, but does not restart a stopped custodian (native-service trials). I understand Endpoint Security entitlement is separate from a lifetime guarantee. Please clarify whether an approved descendant-scoped ES deployment can provide that owner-loss guarantee through a documented API, whether another supported facility is appropriate, or whether meeting this contract requires a VM boundary. Below are the relevant parts of a focused C command-line reproduction (192 lines total, Xcode 27.0, SDK 27.0, -Wall -Wextra -Werror, no signing or third-party libraries). The code ran in the isolated VM; the packaged Xcode project has only been build-checked. 1. The owner installs a protected exception handler on itself, then forks the workload. No cleanup callback follows. static const exception_mask_t masks = EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_BREAKPOINT; static const exception_behavior_t behavior = EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES; mach_port_t channel = MACH_PORT_NULL; mach_port_options_t options = {.flags = MPO_EXCEPTION_PORT | MPO_INSERT_SEND_RIGHT}; kern_return_t rc = mach_port_construct(mach_task_self(), &options, 0, &channel); if (rc != KERN_SUCCESS) return 4; rc = task_set_exception_ports(mach_task_self(), masks, channel, behavior, THREAD_STATE_NONE); if (rc != KERN_SUCCESS) return 4; pid_t child = fork(); if (!child) { /* Ordinary receive rights are not inherited. Only the kernel's task * exception-handler state provides supervision of this child. */ _exit(payload(directory, mode, exe)); } 2. The workload detaches (double-fork shown; fork, setsid and posix_spawn SETPGROUP/SETSID also tested; a child can also clear the handler with task_set_exception_ports(..., MACH_PORT_NULL, ...)). child = fork(); if (!child) { if (strcmp(mode, "fork") && setsid() < 0) _exit(4); if (!strcmp(mode, "double-fork")) { pid_t second = fork(); if (second < 0) _exit(4); if (second) _exit(0); } child_work(directory, mode); } 3. Each member reads its inherited handler state and keeps running ordinary BSD syscalls and a Mach trap. kern_return_t rc = task_get_exception_ports(mach_task_self(), masks, observed, &count, ports, behaviors, flavors); /* port == MACH_PORT_DEAD -> dead_mask, valid send right -> live_mask */ for (;;) { if (write(fd, ".", 1) != 1) _exit(3); /* heartbeat file */ (void)getpid(); mach_port_t thread = mach_thread_self(); mach_port_deallocate(mach_task_self(), thread); usleep(10000); } Observed output (double-fork case, original VM run). Workload, before and after SIGKILL of the owner (pid 1472): {"kind":"exception_state","role":"root","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"late-child","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"root","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} {"kind":"exception_state","role":"late-child","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} After owner loss, both root (pid 1473) and the detached late-child (pid 1475, own session) were still alive under the same uniqueid/pidversion, reparented to launchd, with heartbeat files still growing. Across 21 owner-death trials in 7 modes, 39 known fixture processes survived and no case left the fixture empty. The 3 breakpoint controls (owner alive) confirmed real exception delivery. Expected contract: a documented kernel-owned boundary prevents continued execution by every inherited member after all control owners disappear, without enumerating descendants after the fact or requiring workload cooperation. I am asking which supported macOS API meets that contract, not asserting that exception ports promise it. Apple DTS asked me to start this thread (Case-ID: 22799543) and will review once I reply with the link. The full reproduction steps and environment details are in the attached text. forum-attachment-reproduction.txt
0
0
31
11h
Diagnosing pre-main latency in a short-lived macOS child process while preserving its parent
I’m looking for a supported way to investigate startup latency before main() in a short-lived native macOS child process, while preserving its original parent-child relationship. Environment macOS 26.6.2, build 25G83. Native arm64 executables. The on-disk /usr/lib/dyld contains the identifier dyld-1387; this is a static observation, not independent verification of all runtime shared-cache components. The diagnostic runs were started manually from normal macOS Terminal. All inputs and target processes are synthetic test fixtures. Execution structure Test supervisor → Watchdog → Observer → Query Observer launches Query using posix_spawn(). Query checks a synthetic target process’s identity using Security.framework and produces a fixed 28-byte result. Observer passes an explicit environment containing only LANG=C and LC_ALL=C. Consequently, exporting DYLD variables in the outer Terminal would not pass them to Query. Our existing test has a 1000 ms Query deadline and requires empty Query stderr. This is an application-defined acceptance requirement, not a claimed macOS timing guarantee. Observed results A historical full regression run timed out at approximately 1001 ms, with no Query result bytes received. That run did not have main-entry instrumentation, so we cannot determine where its time was spent. A later isolated, instrumented run measured: posix_spawn return to Query main entry: 832.687 ms main entry to return: 24.179 ms Observer-measured Query elapsed time: 864 ms Another isolated, instrumented run measured: posix_spawn call duration: 0.179 ms spawn return to main entry: 634.334 ms main entry to return: 6.757 ms Observer-measured Query elapsed time: 647 ms In the third run, getrusage(RUSAGE_SELF) at main entry reported cumulative CPU time of 3.014 ms user and 2.583 ms system. Before main returned, the cumulative total was 8.088 ms. Timeline measurements used CLOCK_MONOTONIC. Interpretation limits These successful diagnostic runs do not explain or resolve the historical timeout. Instrumentation changes the executable, and cache state and scheduling may differ. The CPU and wall-clock measurements cover different intervals. Subtracting them would not give an exact waiting-time measurement. We cannot currently attribute the delay to dyld, scheduling, security checks, IPC, or I/O. Diagnostic constraints We want to preserve the original parent-child relationship and avoid system-wide collection, disabling security protections, or silently changing permissions. We have not established that the Instruments App Launch configuration available to us can capture this child’s earliest startup phases while restricting collection to Query. The historical DYLD_PRINT_STATISTICS options are not documented in the installed dyld manual. Attaching a sampling tool after obtaining the PID may miss the relevant startup interval and may perturb this short-lived process. Questions What supported tool or API on this macOS version can distinguish startup phases before main() for this posix_spawn-created child? Can collection itself be restricted to Query, rather than collecting system-wide data and filtering the report afterward? What permissions are required, which early phases remain unobservable, and how much observer perturbation should we expect? If these constraints cannot all be met, what is the smallest necessary change to the diagnostic setup? What minimal sample project and evidence would be most useful for further investigation? I have preserved the original failure and subsequent diagnostic evidence, but do not yet have a standalone Xcode sample that reliably reproduces the historical timeout. I’m requesting guidance on an appropriate measurement method, not asserting that this is a confirmed macOS defect.
0
0
19
16h
How to distinguish a foreground cold launch from a background task cold launch?
I'm trying to determine why my UIKit application was launched, specifically whether it was launched by the user or by the system to execute a background task. I recently added a BGProcessingTask to update data overnight. Consider this scenario: The user backgrounds the app at 10 AM. A background task is scheduled with earliestBeginDate set to 4 AM the following day. During those 18 hours, iOS terminates the app's process to reclaim memory. iOS later decides to execute the scheduled background task and launches a new app process in the background. My understanding is that this results in a cold launch, including a call to application(_:didFinishLaunchingWithOptions:) and the initialization performed there. This matters because some of our startup initialization triggers network requests that are unnecessary when the app is launched only to perform a background task. Questions 1. Can iOS relaunch a previously terminated app to execute a scheduled BGProcessingTask? I'm referring specifically to termination by the system (for example, memory pressure), not the user force-quitting the application. 2. Is there a reliable way to distinguish a foreground cold launch from a background task cold launch inside application(_:didFinishLaunchingWithOptions:)? I tried checking UIApplication.shared.applicationState, but in my testing it was .background during didFinishLaunchingWithOptions in both scenarios, including when the user launched the app by tapping its icon. Is there another documented API or launch context that reliably identifies why the process was started? I'm aware that iOS provides launch options for certain launch scenarios, but I'm specifically interested in distinguishing a background task-triggered cold launch from a user-initiated foreground cold launch. 3. If this distinction cannot be made reliably during didFinishLaunchingWithOptions, what is the earliest lifecycle callback where I can determine that the app is entering the foreground? For example, should foreground-specific initialization be deferred until scene(_:willConnectTo:options:), sceneWillEnterForeground(_:), or another callback? I'm specifically looking for a documented and reliable lifecycle signal, rather than heuristics or arbitrary delays. The goal is to avoid unnecessary startup initialization and network requests when iOS launches the application solely to execute a background task.
0
0
37
17h
macOS XPC: Can incoming message size be bounded before payload allocation?
Hello, I'm designing a local macOS helper service (minimum deployment target: macOS 13) that performs one fixed syntax-validation operation. The submitted source is never executed. The security contract requires: A maximum incoming transport request size of 327,680 bytes. Immediate rejection when the 327,681st byte is encountered, without an allocation proportional to an unbounded sender-controlled payload. No application-level response for an oversized transport request, followed by termination of the affected connection. Complete application responses limited to 65,536 bytes, without treating truncated output as successful. I've reviewed the public XPC APIs, including xpc_data_get_length, xpc_connection_cancel, and xpc_connection_set_peer_code_signing_requirement. The remaining uncertainty is whether XPC can enforce a receiver-side message-size limit before materializing the incoming payload. My questions are: Does any public XPC API on macOS 13+ provide a documented maximum incoming message size that is enforced before payload materialization or proportional allocation? If not, is the entire incoming XPC message necessarily materialized before the application event handler receives it? Is there a supported XPC design for guaranteeing bounded receiver memory with untrusted input, or should this requirement use a different local transport, such as an AF_UNIX SOCK_STREAM socket? What guarantees does xpc_connection_cancel provide regarding connection termination, pending messages, and prevention of connection reuse after detecting malformed or oversized input? I'm specifically looking for documented platform guarantees rather than behavior that happens to work in testing. Thank you!
3
0
142
1d
macOS 14+: Safely supervising worker-created child processes.
Hello Apple Developer Community, We are developing a macOS application with a minimum deployment target of macOS 14.0. We are investigating a process-supervision safety problem involving the following topology: Root → Worker → Child The Worker creates the Child using native process APIs and is responsible for supervising its lifecycle. The critical failure scenario Worker successfully creates Child. Child exists, but its verified process identity has not yet been communicated to Root. Worker unexpectedly terminates before completing the identity handoff. Root must avoid signaling an unrelated process while ensuring that an untracked Child cannot continue executing without authorization. Our safety requirements Independently establish Child's exact process-lifetime identity. Prevent unsafe process signaling caused by PID reuse. Handle Worker failure before identity handoff. Verify process termination and disposition. Avoid relying on private APIs or restricted entitlements. Maintain compatibility with macOS 14 and later. What we have investigated We have reviewed posix_spawn, waitpid, process observation APIs, audit-token-based process identification and signaling, Endpoint Security, and launchd-based supervision. We understand that Endpoint Security FORK events are notifications rather than authorization events, and that dropped notifications may prevent complete birth tracking. We also found es_new_descendants_client in the macOS 27 SDK, but it requires an Endpoint Security entitlement and does not meet our current macOS 14 deployment requirements. We understand that a process cannot automatically use waitpid to reap a grandchild merely because the intermediate parent has terminated. Our questions Is there a publicly supported macOS 14+ API or process-supervision mechanism that can reliably establish the identity of a Worker-created Child even if Worker terminates before communicating that identity? Is there a supported approach for safely containing such a Child when its identity is not yet known to Root? Can audit-token-based signaling provide sufficient process-lifetime identity guarantees for this scenario, and what minimum macOS version supports the relevant APIs? Is there a supported mechanism for independently verifying Child termination when Root is not its direct parent? If this cannot be guaranteed using public APIs, would Apple recommend changing the architecture so that Root directly creates and supervises Child? We are not requesting private API access or Endpoint Security entitlements. We would appreciate guidance on the supported macOS process-lifecycle contracts before proceeding with implementation. Thank you for your assistance.
5
0
437
1d
C-XPC on macOS 14: Do connection EUID/ASID and message-derived SecCode identify the same sender?
Platform / environment Minimum deployment target: macOS 14.0. Development environment: macOS 26.3, Xcode 26.6, macOS SDK 26.5, Swift 6.3.3. We are evaluating public C-XPC and Security.framework APIs; we have not yet validated this identity model over a real C-XPC connection. Context A per-user, signed Runtime Host accepts a connection from a separately signed client. Let peer be the accepted C-XPC peer connection, and receivedMessage the original request dictionary delivered by that connection's event handler. Our admission policy requires both (a) the effective UID and audit session of the actual message sender and (b) validation of that sender's dynamic code against an independently configured code-signing requirement. No application-level authority is granted before these checks. API sequence under review We would first read xpc_connection_get_euid(peer) and xpc_connection_get_asid(peer), then obtain a dynamic code reference via SecCodeCreateWithXPCMessage(receivedMessage, kSecCSDefaultFlags, &code). We would validate that reference with SecCodeCheckValidity(code, kSecCSDefaultFlags, approvedRequirement), where approvedRequirement is configured independently of the peer, and finally inspect the required signing information with SecCodeCopySigningInformation. Reading signing information is not a substitute for code validation. Question On macOS 14, is there a documented, supported guarantee that the connection-level EUID/ASID and the message-derived SecCode refer to the same process occurrence and the actual sender of this particular received request? The connection getters describe attributes captured when the connection was established, while SecCodeCreateWithXPCMessage derives a dynamic-code reference from the original received XPC dictionary. We do not assume that these APIs provide an atomic identity snapshot or prove that their observations refer to the same sender process instance. In particular, what are the limits of any such guarantee when messages or messaging capabilities are forwarded, a process calls exec, a process exits or is replaced, credentials or audit sessions change, or a connection is interrupted and re-established? What if the sender's state changes between message reception and completion of the validation sequence? Request for a supported alternative If this API sequence does not establish that correspondence, which public APIs available on macOS 14 can provide the effective UID, audit session ID, and dynamic-code identity from the same received-message provenance? We are not considering PID-only lookup, private audit-token access, or caller-supplied identity claims. A clarification that the requested guarantee is unavailable would also be valuable. References xpc_connection_get_euid xpc_connection_get_asid Apple DTS: Validating Signature Of XPC Process
0
0
51
5d
Supported completeness and lifecycle guarantees for es_new_descendants_client
Hello Apple Developer Technical Support, I am evaluating es_new_descendants_client for a local command runner that must report success only after its workload and every process descended from that workload have exited. If observation is incomplete or ambiguous, the runner must report failure. This is a design inquiry, not a report of a reproduced operating-system defect; no entitled prototype has been tested. The proposed observer would create its client and subscribe to lifecycle notifications before launching any workload. It would maintain a registry using process-lifetime identities, add processes on creation and remove them on exit. An unmatched event, missing required field, detected loss or observer failure would invalidate the run. It would consider closure only after all registered workload processes had exited. We have not established that these rules are sufficient. Could you clarify which of the following properties are supported API guarantees, and identify any that applications must not rely on? A documented reference or an explicit statement that a guarantee is unavailable would both help. Please identify applicable macOS/SDK versions and any known version-dependent limitations. 1. Membership and creation-event coverage Does the observed subtree retain a process and all of its future descendants after its original parent exits, it is reparented, it double-forks, or it changes process group/session with setpgid or setsid? Could a process remain observable for exit while creation events for its children become invisible? For a workload launched after successful subscription, does every successful process-creation path—including fork, vfork and posix_spawn—produce a lifecycle event sufficient to register the new process before closure can be declared? Which event and identity fields should be used for each path, including a child that exits without a successful exec? Does the calling observer receive the necessary event for its own initial workload launch? 2. Ordering and the meaning of exit Is there a supported per-client ordering guarantee that every child-creation event from a process is delivered before that process's exit notification, including concurrent creation and exit? Can the child's events arrive before the event that introduces that child? Please distinguish kernel enqueue order, handler delivery order and any processing order the application must impose. At what lifecycle boundary is ES_EVENT_TYPE_NOTIFY_EXIT generated? Does it establish that the identified process can no longer execute or initiate writes, or can relevant activity continue after the notification? We would not equate process exit with filesystem durability or completion of work already delegated to other processes. 3. Muting and other visibility filters Does a newly created descendants client have default process, path or target-path mutes that can suppress fork/exit notifications? What supported sequence of configuration and inspection calls establishes complete lifecycle visibility before launch, including mute inversion and executable-path changes? Apart from subscription and muting, are there policy, security, rate-limit or client-type exclusions that can suppress those events? Which suppressed events, if any, are intentionally absent from the sequence counter rather than reported as drops? 4. Sequence numbers and loss detection The global_seq_num documentation requires message version greater than 4. Is that field guaranteed for descendants-client lifecycle messages? Do notifications concerning the calling observer and its descendants use the same per-client sequence? How can a client establish a valid initial baseline and detect loss before its first received message? Is every dropped subscribed, unmuted lifecycle event reflected in the next delivered sequence number? What counter reset, wraparound or client-recreation rules must be handled? Would the proposed registry rule make terminal loss fail safely—for example, a lost final exit leaves a process registered—under the supported ordering and visibility semantics? Or is there a counterexample in which the registry can become empty while an unobserved descendant survives? 5. Synchronization, observer failure and delegated work Does es_sync_client provide any loss/completeness information beyond draining preceding queued messages? Its documented callbacks also run for a destroyed or null client, so we would not interpret callback arrival alone as successful completion. Is there a supported mechanism to distinguish a healthy drain from invalidation? What does “instigates” cover for this client? In particular, can it observe or attribute work executed by existing launchd/XPC services, or by unrelated processes receiving file descriptors? We would treat such work as outside a lineage-only closure claim unless it is explicitly covered or independently excluded. Does this client provide any supported protection against a same-UID workload stopping, killing or otherwise interfering with its observer, or must that isolation be supplied separately? Observer failure would invalidate the run; we are not assuming ES supplies a write barrier for evidence files. 6. Supported cleanup and deployment Is there a supported public mechanism to signal a non-child descendant by process-lifetime identity, without a PID-reuse race between observing it and sending a signal? Is there a recommended approach if the observer cannot wait on that process? We do not want to depend on private libproc functions as an application contract. Finally, is this use case eligible for com.apple.developer.endpoint-security.client in a standalone signed command-line observer, and what supported signing/provisioning or packaging requirements apply? This is a request for guidance, not an entitlement application. Our central question is whether supported APIs can establish complete descendant-process closure under these constraints. If they cannot, we would appreciate a clear statement of that limitation or a supported alternative. Thank you. Documentation consulted: es_new_descendants_client es_sync_client global_seq_num es_process_t
6
0
789
1w
XPCSession.cancel does not immediately cancel
I'm using an XPCSession to send a message to a service/agent. When calling session.cancel(reason: "stop") the connection is not immediately canceled. The session seems to wait for any pending replies from the service. According to the docs for XPCSession.cancel: When you cancel a session, it discards any unsent messages and invalidates its connection. If there are messages awaiting replies, the session calls the reply handlers with an appropriate XPCRichError. This does seem to imply that messages waiting for replies are immediately canceled, however that's not the case. The service may be busy and may take a while to respond, or it may not reply at all. The session is only canceled after all enqueued messages get a reply from the service. let session = try XPCSession(xpcService: "com.example.listener", cancellationHandler: { print("client session canceled") }) try session.send("Test", replyHandler: { reply in print("reply", reply) }) print("cancel") session.cancel(reason: "cancel") // calls cancellationHandler *after* receiving reply Is that expected behaviour? If the service does not respond at all the XPCService will never be canceled. Compared to xpc_connection_create + xpc_connection_cancel(connection) this does seem to immediately cancel the connection and call the reply_handler and event_handler. This does not wait for pending replies from the service. Is there an alternative way to force cancel an XPCSession? Main goal is to protect against two potential issues: The service is busy and doesn't respond in time. The client fires a timeout and wants to disconnect/reconnect, but the cancellationHandler is not called until service responds. So the timeout is not useful, client needs to wait for a reply anyway. The service does not respond at all. This could for example happen if a Launch Agent is improperly configured. The mach service is registered, but the agent may not launch. Sending a message on the XPCSession will never receive a reply.
3
0
148
1w
Sandboxed helper keeps running after the app is turned off in Background App Activity
Short version: we run a sandboxed helper as a hidden service account, started at boot by an SMAppService daemon. It works, even before login. But when the user turns our app off in Background App Activity, only the daemon stops. The helper keeps running. Is this setup supported, and what's the right way to manage the helper? What we want A Developer ID signed, notarized app (not Mac App Store) with a helper that parses untrusted input. The helper should: run as a dedicated, hidden, non-login local account; use App Sandbox, with its own container; be available before anyone logs in (after FileVault unlock). What we built An unsandboxed root LaunchDaemon, registered with SMAppService.daemon, runs this at boot: launchctl bootstrap user/<serviceUID> <fixed-agent-plist> The agent plist uses LimitLoadToSessionType=Background. The helper is a nested app in the same bundle, with com.apple.security.app-sandbox=true. We don't create a GUI session, change UID after the sandbox starts, or use private APIs. What we measured macOS 27.0 (26A428), arm64, dummy data only: Register and approve: the daemon starts. The helper starts as UID 60000, its container works, and reads outside it are denied. Turn the app off in Background App Activity: the daemon gets SIGTERM and stops. The helper keeps running (same PID). Turn it back on: the daemon starts again. Its bootstrap returns exit 5, because the old helper is still loaded. Call unregister(): the daemon stops. The helper keeps running. Cold boot (tested with a plain /Library/LaunchDaemons job, not yet SMAppService): the helper started and worked before login finished. For comparison, running the same sandboxed helper as a system daemon with UserName set to this account fails before main: Incoming message euid:60000 does not match secinitd uid:0. Questions Is this setup supported for shipping, including the sandbox starting before anyone logs in? Does the approval for daemon-bundled helpers cover a helper bootstrapped into another account's domain? Our plan: when the daemon gets SIGTERM, it runs bootout on the helper and its domain, and it treats bootstrap exit 5 as "already loaded". Is that the intended pattern, or is there a supported way for the helper to follow the app's Background App Activity setting? If this setup isn't supported, what public mechanism gives a sandboxed helper its own non-root identity before login? I can share the plists, entitlements and logs from a minimal reproducer.
6
0
402
1w
AlarmKit custom LiveActivityIntent: can executions overlap or be redelivered across app relaunch?
Hello, I'm developing an iPhone alarm app with AlarmKit. The alert has a custom secondary button whose intent conforms to LiveActivityIntent, declares supportedModes: .background and authenticationPolicy: .alwaysAllowed, and passes an alarm ID to app code from a @MainActor perform() implementation. The intent lives in the app target. It is not shared with a widget or an App Intents extension. The operation persists an in-progress record, awaits scheduling a new alarm, cancels the original only after scheduling succeeds, and then persists completion. After an interruption or relaunch, recovery reads the persisted original and candidate IDs and checks the system's alarm inventory. I want to understand which execution guarantees the app can rely on, so that recovery never schedules a duplicate alarm or cancels a valid candidate. I've read the LiveActivityIntent and App Intents runtime documentation. I understand how execution placement and foreground/background modes are described, but I couldn't find a public guarantee about overlap or redelivery when the app process is replaced. To be clear, I have not observed two simultaneous processes or duplicate execution in this setup. This is a question about what the app may assume, not a bug report. Questions For this app-target LiveActivityIntent configuration on iOS/iPadOS 26.x, can an older process of the same app still be executing an alarm-button intent while a newly launched process begins another invocation? Is there a documented single-process or handover guarantee an app may rely on? I'd appreciate it if the answer could distinguish multiple concurrent invocations within one process from overlap between an old and a newly launched process. Can the same alarm-button action be redelivered after an interruption or relaunch, including after perform() has thrown or returned? Which serialization or at-most-once guarantees, if any, apply to invocations for the same alarm ID, and which duplicate-delivery defenses must the app provide? I'm not assuming that every invocation comes from a new user tap. If the process that issued an AlarmKit scheduling or cancellation request terminates, may the app assume that the request has either completed or been abandoned before a newly launched process calls AlarmKit? If not, which public API checks or sequencing are recommended before recovery modifies the original or candidate alarm? I'm looking for supported app-level assumptions and recommended safeguards, not internal process lifecycle details. The app must preserve valid alarms and must never report an uncertain result as success. The shipping target is iPhone, with a minimum deployment target of 26.1. Earlier isolated testing on an iPad (9th generation, including iPadOS 26.7) did not show the overlap described above. Related question about the alert presentation after an intent error: [https://developer.apple.com/forums/thread/849075] Thank you!
0
0
311
2w
Supported macOS design for safely terminating an app-owned helper subtree?
I am designing a bounded local diagnostic helper for macOS. It would run only purpose-built helpers supplied by the application, not third-party or untrusted code. The design question is how to stop exactly those helpers and their descendants on timeout, without affecting an unrelated process or incorrectly reporting that cleanup is complete. This is a public-API suitability question, not a report of a reproduced macOS bug. The intended diagnostic is not an antivirus or endpoint-detection product. The required properties are: Identify each owned process by its lifetime and association with this helper run, not a numeric PID or process-group ID alone. Account for descendants across fork/exec, parent exit or reparenting, and process-group/session changes. Observing that a descendant escaped is not equivalent to preventing an escape. Terminate only the still-owned processes without a stale-identity race between checking ownership and signaling. Report completion only when all owned descendants have stopped and no new owned descendants can appear. Leader exit, IPC disconnection, or an unauthenticated empty process list would not be sufficient. Lost events or uncertain membership must leave the outcome inconclusive. Which supported public API or service/containment architecture can provide these properties? If they cannot all be guaranteed, which constraint should be changed and what guarantee can the supported alternative actually provide? I have reviewed the documentation for es_new_descendants_client and es_sync_client. The remaining questions are: Is a descendant-scoped Endpoint Security client appropriate for this non-security-product diagnostic? If so, which documented entitlement and packaging route applies? I am asking about eligibility, not assuming it. Does any supported design combine lifetime-safe control with containment of the whole owned subtree, including concurrent descendant creation? Merely receiving events would not establish that property. What additional protocol, if any, makes a synchronization callback sufficient to establish complete termination when client destruction, event loss, and concurrent activity are possible? I am not treating that callback alone as proof that no owned process remains. I can redesign around a helper that cannot create descendants if that is the supported approach. In that case, what supported mechanism enforces that restriction and what termination guarantees remain? So far, a standalone C harness has passed eleven fabricated-input cases with assertions enabled. It exercised no Endpoint Security client, process-tree creation/enumeration/control, or application behavior. It is not a runtime reproducer for this API-design question and does not establish native lifecycle safety. Pointers to documented guarantees, limitations, or an Apple sample would help me choose the architecture before preparing a narrowly scoped native test. I am not seeking private APIs or a way to disable platform protections. No logs, source archive, or binary is attached.
1
0
459
2w
Supported macOS confinement for a supervised process tree
I am evaluating a local diagnostic design before implementation or deployment and need to identify a public, supported macOS confinement mechanism. Proposed arrangement: A privileged custodian remains outside a separate privileged guardian's process group. The guardian launches a fixed diagnostic parent under a dedicated unprivileged identity. That parent sequentially launches three fixed sandboxed Python workloads, one child at a time. The current termination design targets the guardian's process group. It must not rely on whole-host process scans or indiscriminate killing. The proposed sandbox profiles are allow-default with file/network restrictions; the test-child profiles deny process-fork. We have not established that these restrictions prevent an existing process from changing its own group or session. Is there a public, supported interface or configuration that keeps all workload descendants within the supervisor's termination boundary from the initial child transition through final cleanup, while still allowing the parent to launch its authorized sequential children? In particular, please clarify: Escape through setsid/setpgid, spawn attributes, exec or native-library paths. When enforcement begins and whether descendants can relax it. Behavior when the diagnostic parent or guardian exits. Required privileges, entitlements, and supported OS/SDK versions. If the described sandbox categories do not establish that property, please identify the supported alternative boundary, if one exists. A different boundary would require an explicit design change on our side. I am requesting documented interface behavior and limitations—not private sandbox internals, a review of project code, or an absolute termination guarantee during kernel failure. No experiment has been performed to establish this property.
0
0
169
2w
Supported lifecycle and termination guarantees for an embedded macOS XPC service
We are evaluating a lifecycle architecture for a local macOS application and would appreciate guidance on supported public APIs. Proposed architecture: A normally signed, non-root host application. One embedded XPC service with exactly one intended client. No application-created subprocesses inside the service. No privileged helper, persistent LaunchAgent, exported endpoints, private APIs, or reduced system security. One bounded operation per session. Failed or interrupted operations must not automatically be retried. Initial validation would use synthetic workloads only. Our current evaluation target is macOS 15.6 on Apple silicon, using the macOS 15.5 SDK. Please identify any relevant deployment-version limitations. The XPC overview (https://developer.apple.com/documentation/xpc) describes an embedded service as tied to its client's lifetime. We also understand that xpc_connection_cancel (https://developer.apple.com/documentation/xpc/xpc_connection_cancel(_:)) is asynchronous and non-preemptive; we are not treating connection cancellation as proof of service termination. We need clarification on these points: Client death and service startup Does the documented client-lifetime relationship cover client termination, including SIGKILL, during service startup before the first reply? Does it also cover an already running service that is blocked or stopped with SIGSTOP? Which behavior is guaranteed, and which timing or failure cases are intentionally unspecified? Timeout while the client remains alive What supported public mechanism should a normal application use to terminate its own unresponsive embedded service when an operation exceeds its deadline? We want to avoid PID enumeration, PID-reuse races, broad process-group signaling, and exporting a full task-control port. Is there a supported identity-bound termination mechanism? If not, what architecture does Apple recommend? A stopped or hung client remains alive, so we do not assume client-lifetime coupling handles that separate failure case. Observing termination Which public notification reliably identifies the exit of the particular service instance, as distinct from connection invalidation or a missing reply? Because launchd is the parent, the application cannot simply waitpid the service. Is reaping entirely launchd's responsibility, and what completion claim can the application legitimately make? Identity and required privileges Which public signing requirements, launch constraints, sandbox settings, or entitlements are necessary for this architecture? Please distinguish authentication before accepting work from constraints enforced before service code executes. We do not assume peer authentication also grants termination rights. Restart behavior After interruption, cancellation, client exit, or service failure, under what circumstances can launchd or subsequent XPC activity start a replacement service? What supported pattern prevents accidental resubmission or resumption of the same failed operation? We are not asking for hard real-time guarantees during kernel failure, or claiming that forced termination proves callback completion or explicit memory zeroization. If this combination of requirements is unsupported, identifying that boundary and the smallest supported architectural alternative would be a useful answer. Documentation references or a minimal public sample would be welcome.
3
0
254
2w
macOS 27 - my faceless bg-only app now appears in the Dock - how to get rid of that?
My macOS app Find Any File contains another app inside its Resources folder. It's a background-only app that checks if the user presses a hotkey, in which case it launches my app. Since macOS 27, when the hotkey app is running, it appears in the Dock with a "Running in Background" subtitle. That's totally not wanted. How do I make it not appear in the Dock? I've got both "LSBackgroundOnly" and "LSUIElement" set to true in the Info.plist, to no avail.
3
0
268
3w
[27.0beta] Wrong app shown as running in Background in Dock
I develop a tool on macOS which is composed of an UI app to manage the main app settings, and an Agent that runs in background doing some tasks ? (Running the agent is optional, can be launched from the UI app, and can be launched by macOS at startup with SMAppService. ) Agent has the LSUIElement flag set, and only shows a Menu Extra (or whatever it now named), and sometimes some notifications. The whole App package is bundled this way MainAppUI.app/Contents/Library/LoginItems/AppAgent.app (for SMAppService to work) This has been working correctly for years Now on macOS 27 beta, once I quit the UI App, having launched the Agent, the Dock reports the UI App is still running in background (with the grey dot) . But only the Agent is running, not the UI app process. Moreover, System Settings->Background apps reports both the UI app AND the Agent as both requesting to run in background. I would have expected only the Agent being listed in System Settings, and nothing appearing in the Dock. Is this a bug in the OS beta , showing the top-level container bundle as the app running in background instead of the executable direct container ? Or maybe it's on me and I should bundle my app differently ? (I cannot "reverse" the bundle and put the Agent as the main app, with UI "inside", as double clicking the main app should launch the UI App , not the Agent. ) BTW, filed FB23203848 for the same subject. thanks for any direction
3
1
1.1k
3w
Crashe__CFRunLoopServiceMachPort.cold 96% Foreground
Hello, we have encountered a large number of __CFRunLoopServiceMachPort.cold crashes on iOS 26. These crashes frequently occur when the app transitions from the background to the foreground or is launched after sitting idle for a period of time. Despite extensive analysis, we have been unable to find a solution. Currently, the crash data indicates that this issue is specific to iOS 26. We would greatly appreciate your assistance. Thank you very much! Hardware Model: iPhone18,1 OS Version: iPhone OS 26.5.2 (23F84) Release Type: User Baseband Version: 1.60.02 Crash Reporter Key: fda96a4036dcb83e124660e11b654c9484b81dae Incident Identifier: EF18C4DD-7624-42D0-BA72-F17BBC263B16 Time Awake Since Boot: 2900000 seconds Triggered by Thread: 0, Dispatch Queue: com.apple.main-thread Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001917d316c Termination Reason: Namespace SIGNAL, Code 5, Trace/BPT trap: 5 Terminating Process: exc handler [82210] Application Specific Information: (ipc/rcv) invalid name Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 CoreFoundation 0x1917d316c __CFRunLoopServiceMachPort.cold.1 + 64 1 CoreFoundation 0x19168a444 __CFRunLoopServiceMachPort + 416 2 CoreFoundation 0x191654310 __CFRunLoopRun + 1188 3 CoreFoundation 0x19165354c _CFRunLoopRunSpecificWithOptions + 532 4 GraphicsServices 0x236df7498 GSEventRunModal + 120 5 UIKitCore 0x19734c244 -[UIApplication _run] + 796 6 UIKitCore 0x1972b7158 UIApplicationMain + 332 7 KMMVideo 0x1047fe24c 0x104304000 + 5218892 8 dyld 0x18e261c1c start + 6928 Thread 1 name: transmit_hls_7683_193735 Thread 1: 0 libsystem_kernel.dylib 0x2407da5e8 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x1f0852b48 _pthread_cond_wait + 980 2 libc++.1.dylib 0x1a0d5dbcc std::__1::condition_variable::wait(std::__1::unique_lockstd::__1::mutex&) + 32 3 iOSPlayer 0x118cd6114 a_task_runner::worker() + 116 4 iOSPlayer 0x118cd5650 a_task_runner::work_thread() + 196 5 iOSPlayer 0x118cd654c void* std::__1::__thread_proxy[abi:ne200100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_deletestd::__1::__thread_struct>, void (a_task_runner::)(), a_task_runner>>(void*) + 72 6 libsystem_pthread.dylib 0x1f0854438 _pthread_start + 136 7 libsystem_pthread.dylib 0x1f08508cc thread_start + 8 Thread 2: 0 libsystem_kernel.dylib 0x2407d9ed8 read + 8 1 XLTranscodeKit 0x115bb5f4c runtime.read_trampoline.abi0 + 28 Thread 3: Thread 4: 0 libsystem_kernel.dylib 0x2407da5e8 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x1f0852b48 _pthread_cond_wait + 980 2 XLTranscodeKit 0x115bb6648 runtime.pthread_cond_wait_trampoline.abi0 + 24 3 XLTranscodeKit 0x115bb4fb8 runtime.asmcgocall.abi0 + 200 4 ??? 0xd65f03c0 ??? Thread 5: 0 XLTranscodeKit 0x115b3eb68 */bytealg.IndexByteString + 40 1 XLTranscodeKit 0x115b966b8 runtime.findnull + 104 Thread 6: 0 libsystem_kernel.dylib 0x2407db8dc kevent + 8 1 XLTranscodeKit 0x115bb6398 runtime.kevent_trampoline.abi0 + 40 Thread 7: 0 libsystem_kernel.dylib 0x2407da5e8 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x1f0852b48 _pthread_cond_wait + 980 2 XLTranscodeKit 0x115bb6648 runtime.pthread_cond_wait_trampoline.abi0 + 24 3 XLTranscodeKit 0x115bb4fb8 runtime.asmcgocall.abi0 + 200 4 ??? 0xd65f03c0 ???
3
0
469
3w
Can an ExtensionFoundation-based extension on macOS have its own extension point and host its own extensions?
It is possible for an extension to an app (based on ExtensionFoundation) to declare its own extension point and host its own ExtensionFoundation extensions? Based on the documentation, I am guessing the answer is no, but worth double-checking. What would be the reason to prevent this? Every ExtensionFoundation extension runs in its own process, and may have need to be extended safely just as its host app does. Thank you!
3
0
332
3w
Processes & Concurrency Resources
General: DevForums subtopic: App & System Services > Processes & Concurrency Processes & concurrency covers a number of different technologies: Background Tasks Resources Concurrency Resources — This includes Swift concurrency. Service Management Resources XPC Resources Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
1.6k
Activity
Jul ’25
Supported libSystem state after a LaunchDaemon permanently drops privileges
I am testing a fixed signed LaunchDaemon startup program that uses setgroups, setgid and setuid to establish a dedicated non-root identity before loading its service library or creating an application XPC listener. This follows the single-process, deferred-library direction discussed in DTS thread 844906. The remaining question is the supported treatment of system-runtime state initialized before the credential transition. Test environment: Apple silicon, macOS 27.0.1 / Darwin 27.0.0, hardened runtime, no special entitlements. The host links only libSystem and has no application constructors. This is a temporary diagnostic, not an installed product or a file-operation service. Our test verifies real, effective and saved UID/GID, the exact supplementary group vector and failed attempts to regain root. After the transition, a read-only own-task Mach inventory still sees a voucher even though successful task/current-thread voucher getters return null. It also sees one send+receive endpoint without an alias to any of the queried special/registered roles. Ordinary hardened launchd controls in both the login GUI and user domains also have a voucher and such an endpoint. Their recorded endpoint attributes match the post-drop test: empty queue, sequence 1, make-send count 1, send rights present, no send-once rights, port sets or notification requests. We do not treat this as proof that the objects or authority are equivalent. No messages are sent to the unidentified endpoint and no runtime-owned rights are destroyed. In a separate ordinary-user test, public voucher recipe extraction reports only a BANK attribute. Published libdispatch source describes a default task-bank voucher stored separately from the current thread's voucher slot. Published XNU source captures identity when bank context is initialized. We have not established the corresponding lifecycle or authority implications on this OS release, and do not claim that the observed voucher retains root authority. For this startup arrangement, what supported public contract should an application use to establish that libSystem's retained runtime context does not preserve usable pre-drop administrator authority before loading service code? Is there a supported sanitization step, or a specific documented OS trust assumption under which leaving that state intact is intended? If the combination of exact group reduction, deferred service loading and launchd Mach-service check-in cannot support that boundary, which public architecture should we use instead? We are seeking a documented arrangement or a clear limit on the guarantee, rather than a private reset API or an explanation of every internal endpoint. We have not used same-PID exec, a root supervisor, private APIs, or a broad port-type allowlist. Relevant documentation or a minimal public sample would help.
Replies
0
Boosts
0
Views
106
Activity
5h
Subprocess ownership and timeout recovery on Intel macOS Monterey
Hi Quinn, Following your recommendation by email, I’m posting this as a new thread. Thank you again for your guidance on Virtualization.framework. This is a separate question about ordinary host-side subprocess ownership and timeout recovery, not VM cleanup. Target environment: Intel x86_64 macOS Monterey 12.7.6, build 21H1320 Python 3.13.15 Public, supported mechanisms; no root privileges, private APIs or kernel extensions We are verifying a subprocess supervision component with this process structure: Trusted caller process → runner → pytest → private helper → native subprocess Each parent normally owns the consuming wait for its direct child. The private helper exclusively manages signalling and reaping of its native child. Outer processes do not signal saved helper/native PIDs. Cancellation is cooperative, through channels and file/token delivery. The runner observes its fresh pytest child, drains stdout/stderr with bounded retention, and consumes its exact child’s status after exit is observed. The runner, pytest and helper are launched in separate sessions. Consequently, signalling pytest’s process group would not cover the separately sessioned helper and its native child. The unresolved failure case is: A fresh pytest invocation starts. Cancellation delivery fails, or delivery succeeds but the work does not finish. The runner continues observation and bounded output draining within the remaining deadline. The deadline expires while pytest or processes below it may still be alive. The runner reports an unresolved outcome and may exit. The caller also has a bounded deadline and may return without consuming its runner child. Closing capture pipes can cause EPIPE and disturb the child’s cleanup. Exiting a consuming parent also relinquishes its ability to collect that child’s eventual status. The outer caller does not automatically acquire wait rights over pytest or its descendants. Our current policy retains affected files, preserves the original failure, and prevents subsequent tests from starting. We do not treat cancellation delivery, pipe EOF, successful signal delivery, or direct-child reap as proof that every descendant has stopped. This prevents false success, but does not resolve responsibility for work that remains alive. We have considered separating the caller’s response lifetime from the consuming owners’ lifetimes: the caller could return an unresolved response while both existing parents remain alive, draining output and collecting their direct children later. However, keeping them alive adds no termination authority and does not address a crash of either owner. I am not asking for an absolute guarantee against arbitrary kernel failures, or a promise that SIGKILL always completes within a fixed time. I would like to understand the supported architectural approach on Monterey. My questions are: Is retaining the existing consuming parents beyond the response deadline the appropriate pattern, or is there a supported macOS facility that provides a better ownership and recovery boundary? What safe termination authority should those owners retain over their fresh direct children? If process groups are part of the solution, what lifecycle rules are needed to avoid acting on a reused identifier, particularly after leader exit or reaping? Is there a supported way to manage the separately sessioned helper/native work if an intermediate parent exits? Or must each level independently retain its own supervision and cleanup responsibility? If the consuming owner itself crashes, is there a supported recovery mechanism for ordinary subprocesses? Would launchd or XPC materially help, and what limitations would remain for descendants in separate sessions? Which design constraint would you recommend changing: cooperative-only cancellation, the fixed lifetime of the runner, or the process topology? These are our current choices, not restrictions we assume macOS imposes. Our practical goal is a bounded response while an identifiable owner remains responsible for unsettled work, with appropriate termination authority and an honest unresolved outcome when cleanup cannot be established. The immediate qualification scope is only three simple tests, using shell bodies such as exit, kill -9 $$, and echo with ordinary exit statuses. They contain no intentional background work, pipelines or command substitutions. We would prefer a proportionate supported pattern rather than a new general supervision framework. If a reduced example would help clarify the question, I can provide one. Thank you for your time and guidance.
Replies
4
Boosts
0
Views
72
Activity
10h
macOS: supported process-tree lifetime boundary after supervisor loss
I am building Ouroboros (ouro-jail), a contained developer workload runner. Before advertising native macOS support, I need a supported lifetime boundary that covers ordinary fork/spawn/exec descendants, including detached sessions and double-fork daemons. Execution must stay contained when every userspace custodian dies, rather than relying on a surviving process to enumerate and kill descendants. Does macOS provide a supported facility that can: Establish an immutable workload scope before its first instruction and atomically inherit membership through fork/spawn/exec, without modifying the workload or preventing ordinary Node, shell and Git subprocess behavior? Stop or terminate every member after loss of the final control owner, with enforcement retained in the kernel and no userspace callback required? Handle concurrent creation during teardown and expose a verifiable final drain, using stable process identities rather than PID-only scans? Development evidence on macOS 27.0 build 26A428, XNU 13432.1.9 (isolated VM, SIP already disabled in the guest; this is development evidence, not normal-SIP qualification): Descendant-scoped Endpoint Security clients observe the tested subtree. Reciprocal custodians handle either client's loss, but killing both leaves all known members running. Uncached fail-closed AUTH_EXEC lets a survivor execute a new command after both clients disappear (200 reciprocal-custody trials). PT_ATTACHEXC gives kernel-enforced debugger-death cleanup for attached targets, but later fork/spawn children survive (80 debugger-lifetime trials). A locally installed, identity-protected Mach exception handler is inherited through the tested fork/spawn/exec paths. Owner death changes it to a dead handler without stopping normal execution; a child can clear it. Breakpoint controls confirm real kernel exception delivery (24 Mach-lifetime trials). Published XNU contains per-task fatal-port no-senders cleanup, but machdep.task_get_fatal_port is absent on this tested release kernel. I have not treated it as a supported application API. LaunchServices creates a real application coalition, and XPC service lifetime follows app death. However, all seven workload descendants survive, retain coalition membership and can execute a new command. Shared and private audit sessions both fail; eight-second follow-ups also retain all seven survivors. A temporary root launchd service restarts and reaps seven recorded processes after a crash, but does not restart a stopped custodian (native-service trials). I understand Endpoint Security entitlement is separate from a lifetime guarantee. Please clarify whether an approved descendant-scoped ES deployment can provide that owner-loss guarantee through a documented API, whether another supported facility is appropriate, or whether meeting this contract requires a VM boundary. Below are the relevant parts of a focused C command-line reproduction (192 lines total, Xcode 27.0, SDK 27.0, -Wall -Wextra -Werror, no signing or third-party libraries). The code ran in the isolated VM; the packaged Xcode project has only been build-checked. 1. The owner installs a protected exception handler on itself, then forks the workload. No cleanup callback follows. static const exception_mask_t masks = EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_BREAKPOINT; static const exception_behavior_t behavior = EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES; mach_port_t channel = MACH_PORT_NULL; mach_port_options_t options = {.flags = MPO_EXCEPTION_PORT | MPO_INSERT_SEND_RIGHT}; kern_return_t rc = mach_port_construct(mach_task_self(), &options, 0, &channel); if (rc != KERN_SUCCESS) return 4; rc = task_set_exception_ports(mach_task_self(), masks, channel, behavior, THREAD_STATE_NONE); if (rc != KERN_SUCCESS) return 4; pid_t child = fork(); if (!child) { /* Ordinary receive rights are not inherited. Only the kernel's task * exception-handler state provides supervision of this child. */ _exit(payload(directory, mode, exe)); } 2. The workload detaches (double-fork shown; fork, setsid and posix_spawn SETPGROUP/SETSID also tested; a child can also clear the handler with task_set_exception_ports(..., MACH_PORT_NULL, ...)). child = fork(); if (!child) { if (strcmp(mode, "fork") && setsid() < 0) _exit(4); if (!strcmp(mode, "double-fork")) { pid_t second = fork(); if (second < 0) _exit(4); if (second) _exit(0); } child_work(directory, mode); } 3. Each member reads its inherited handler state and keeps running ordinary BSD syscalls and a Mach trap. kern_return_t rc = task_get_exception_ports(mach_task_self(), masks, observed, &count, ports, behaviors, flavors); /* port == MACH_PORT_DEAD -> dead_mask, valid send right -> live_mask */ for (;;) { if (write(fd, ".", 1) != 1) _exit(3); /* heartbeat file */ (void)getpid(); mach_port_t thread = mach_thread_self(); mach_port_deallocate(mach_task_self(), thread); usleep(10000); } Observed output (double-fork case, original VM run). Workload, before and after SIGKILL of the owner (pid 1472): {"kind":"exception_state","role":"root","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"late-child","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"root","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} {"kind":"exception_state","role":"late-child","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} After owner loss, both root (pid 1473) and the detached late-child (pid 1475, own session) were still alive under the same uniqueid/pidversion, reparented to launchd, with heartbeat files still growing. Across 21 owner-death trials in 7 modes, 39 known fixture processes survived and no case left the fixture empty. The 3 breakpoint controls (owner alive) confirmed real exception delivery. Expected contract: a documented kernel-owned boundary prevents continued execution by every inherited member after all control owners disappear, without enumerating descendants after the fact or requiring workload cooperation. I am asking which supported macOS API meets that contract, not asserting that exception ports promise it. Apple DTS asked me to start this thread (Case-ID: 22799543) and will review once I reply with the link. The full reproduction steps and environment details are in the attached text. forum-attachment-reproduction.txt
Replies
0
Boosts
0
Views
31
Activity
11h
Diagnosing pre-main latency in a short-lived macOS child process while preserving its parent
I’m looking for a supported way to investigate startup latency before main() in a short-lived native macOS child process, while preserving its original parent-child relationship. Environment macOS 26.6.2, build 25G83. Native arm64 executables. The on-disk /usr/lib/dyld contains the identifier dyld-1387; this is a static observation, not independent verification of all runtime shared-cache components. The diagnostic runs were started manually from normal macOS Terminal. All inputs and target processes are synthetic test fixtures. Execution structure Test supervisor → Watchdog → Observer → Query Observer launches Query using posix_spawn(). Query checks a synthetic target process’s identity using Security.framework and produces a fixed 28-byte result. Observer passes an explicit environment containing only LANG=C and LC_ALL=C. Consequently, exporting DYLD variables in the outer Terminal would not pass them to Query. Our existing test has a 1000 ms Query deadline and requires empty Query stderr. This is an application-defined acceptance requirement, not a claimed macOS timing guarantee. Observed results A historical full regression run timed out at approximately 1001 ms, with no Query result bytes received. That run did not have main-entry instrumentation, so we cannot determine where its time was spent. A later isolated, instrumented run measured: posix_spawn return to Query main entry: 832.687 ms main entry to return: 24.179 ms Observer-measured Query elapsed time: 864 ms Another isolated, instrumented run measured: posix_spawn call duration: 0.179 ms spawn return to main entry: 634.334 ms main entry to return: 6.757 ms Observer-measured Query elapsed time: 647 ms In the third run, getrusage(RUSAGE_SELF) at main entry reported cumulative CPU time of 3.014 ms user and 2.583 ms system. Before main returned, the cumulative total was 8.088 ms. Timeline measurements used CLOCK_MONOTONIC. Interpretation limits These successful diagnostic runs do not explain or resolve the historical timeout. Instrumentation changes the executable, and cache state and scheduling may differ. The CPU and wall-clock measurements cover different intervals. Subtracting them would not give an exact waiting-time measurement. We cannot currently attribute the delay to dyld, scheduling, security checks, IPC, or I/O. Diagnostic constraints We want to preserve the original parent-child relationship and avoid system-wide collection, disabling security protections, or silently changing permissions. We have not established that the Instruments App Launch configuration available to us can capture this child’s earliest startup phases while restricting collection to Query. The historical DYLD_PRINT_STATISTICS options are not documented in the installed dyld manual. Attaching a sampling tool after obtaining the PID may miss the relevant startup interval and may perturb this short-lived process. Questions What supported tool or API on this macOS version can distinguish startup phases before main() for this posix_spawn-created child? Can collection itself be restricted to Query, rather than collecting system-wide data and filtering the report afterward? What permissions are required, which early phases remain unobservable, and how much observer perturbation should we expect? If these constraints cannot all be met, what is the smallest necessary change to the diagnostic setup? What minimal sample project and evidence would be most useful for further investigation? I have preserved the original failure and subsequent diagnostic evidence, but do not yet have a standalone Xcode sample that reliably reproduces the historical timeout. I’m requesting guidance on an appropriate measurement method, not asserting that this is a confirmed macOS defect.
Replies
0
Boosts
0
Views
19
Activity
16h
How to distinguish a foreground cold launch from a background task cold launch?
I'm trying to determine why my UIKit application was launched, specifically whether it was launched by the user or by the system to execute a background task. I recently added a BGProcessingTask to update data overnight. Consider this scenario: The user backgrounds the app at 10 AM. A background task is scheduled with earliestBeginDate set to 4 AM the following day. During those 18 hours, iOS terminates the app's process to reclaim memory. iOS later decides to execute the scheduled background task and launches a new app process in the background. My understanding is that this results in a cold launch, including a call to application(_:didFinishLaunchingWithOptions:) and the initialization performed there. This matters because some of our startup initialization triggers network requests that are unnecessary when the app is launched only to perform a background task. Questions 1. Can iOS relaunch a previously terminated app to execute a scheduled BGProcessingTask? I'm referring specifically to termination by the system (for example, memory pressure), not the user force-quitting the application. 2. Is there a reliable way to distinguish a foreground cold launch from a background task cold launch inside application(_:didFinishLaunchingWithOptions:)? I tried checking UIApplication.shared.applicationState, but in my testing it was .background during didFinishLaunchingWithOptions in both scenarios, including when the user launched the app by tapping its icon. Is there another documented API or launch context that reliably identifies why the process was started? I'm aware that iOS provides launch options for certain launch scenarios, but I'm specifically interested in distinguishing a background task-triggered cold launch from a user-initiated foreground cold launch. 3. If this distinction cannot be made reliably during didFinishLaunchingWithOptions, what is the earliest lifecycle callback where I can determine that the app is entering the foreground? For example, should foreground-specific initialization be deferred until scene(_:willConnectTo:options:), sceneWillEnterForeground(_:), or another callback? I'm specifically looking for a documented and reliable lifecycle signal, rather than heuristics or arbitrary delays. The goal is to avoid unnecessary startup initialization and network requests when iOS launches the application solely to execute a background task.
Replies
0
Boosts
0
Views
37
Activity
17h
macOS XPC: Can incoming message size be bounded before payload allocation?
Hello, I'm designing a local macOS helper service (minimum deployment target: macOS 13) that performs one fixed syntax-validation operation. The submitted source is never executed. The security contract requires: A maximum incoming transport request size of 327,680 bytes. Immediate rejection when the 327,681st byte is encountered, without an allocation proportional to an unbounded sender-controlled payload. No application-level response for an oversized transport request, followed by termination of the affected connection. Complete application responses limited to 65,536 bytes, without treating truncated output as successful. I've reviewed the public XPC APIs, including xpc_data_get_length, xpc_connection_cancel, and xpc_connection_set_peer_code_signing_requirement. The remaining uncertainty is whether XPC can enforce a receiver-side message-size limit before materializing the incoming payload. My questions are: Does any public XPC API on macOS 13+ provide a documented maximum incoming message size that is enforced before payload materialization or proportional allocation? If not, is the entire incoming XPC message necessarily materialized before the application event handler receives it? Is there a supported XPC design for guaranteeing bounded receiver memory with untrusted input, or should this requirement use a different local transport, such as an AF_UNIX SOCK_STREAM socket? What guarantees does xpc_connection_cancel provide regarding connection termination, pending messages, and prevention of connection reuse after detecting malformed or oversized input? I'm specifically looking for documented platform guarantees rather than behavior that happens to work in testing. Thank you!
Replies
3
Boosts
0
Views
142
Activity
1d
macOS 14+: Safely supervising worker-created child processes.
Hello Apple Developer Community, We are developing a macOS application with a minimum deployment target of macOS 14.0. We are investigating a process-supervision safety problem involving the following topology: Root → Worker → Child The Worker creates the Child using native process APIs and is responsible for supervising its lifecycle. The critical failure scenario Worker successfully creates Child. Child exists, but its verified process identity has not yet been communicated to Root. Worker unexpectedly terminates before completing the identity handoff. Root must avoid signaling an unrelated process while ensuring that an untracked Child cannot continue executing without authorization. Our safety requirements Independently establish Child's exact process-lifetime identity. Prevent unsafe process signaling caused by PID reuse. Handle Worker failure before identity handoff. Verify process termination and disposition. Avoid relying on private APIs or restricted entitlements. Maintain compatibility with macOS 14 and later. What we have investigated We have reviewed posix_spawn, waitpid, process observation APIs, audit-token-based process identification and signaling, Endpoint Security, and launchd-based supervision. We understand that Endpoint Security FORK events are notifications rather than authorization events, and that dropped notifications may prevent complete birth tracking. We also found es_new_descendants_client in the macOS 27 SDK, but it requires an Endpoint Security entitlement and does not meet our current macOS 14 deployment requirements. We understand that a process cannot automatically use waitpid to reap a grandchild merely because the intermediate parent has terminated. Our questions Is there a publicly supported macOS 14+ API or process-supervision mechanism that can reliably establish the identity of a Worker-created Child even if Worker terminates before communicating that identity? Is there a supported approach for safely containing such a Child when its identity is not yet known to Root? Can audit-token-based signaling provide sufficient process-lifetime identity guarantees for this scenario, and what minimum macOS version supports the relevant APIs? Is there a supported mechanism for independently verifying Child termination when Root is not its direct parent? If this cannot be guaranteed using public APIs, would Apple recommend changing the architecture so that Root directly creates and supervises Child? We are not requesting private API access or Endpoint Security entitlements. We would appreciate guidance on the supported macOS process-lifecycle contracts before proceeding with implementation. Thank you for your assistance.
Replies
5
Boosts
0
Views
437
Activity
1d
C-XPC on macOS 14: Do connection EUID/ASID and message-derived SecCode identify the same sender?
Platform / environment Minimum deployment target: macOS 14.0. Development environment: macOS 26.3, Xcode 26.6, macOS SDK 26.5, Swift 6.3.3. We are evaluating public C-XPC and Security.framework APIs; we have not yet validated this identity model over a real C-XPC connection. Context A per-user, signed Runtime Host accepts a connection from a separately signed client. Let peer be the accepted C-XPC peer connection, and receivedMessage the original request dictionary delivered by that connection's event handler. Our admission policy requires both (a) the effective UID and audit session of the actual message sender and (b) validation of that sender's dynamic code against an independently configured code-signing requirement. No application-level authority is granted before these checks. API sequence under review We would first read xpc_connection_get_euid(peer) and xpc_connection_get_asid(peer), then obtain a dynamic code reference via SecCodeCreateWithXPCMessage(receivedMessage, kSecCSDefaultFlags, &code). We would validate that reference with SecCodeCheckValidity(code, kSecCSDefaultFlags, approvedRequirement), where approvedRequirement is configured independently of the peer, and finally inspect the required signing information with SecCodeCopySigningInformation. Reading signing information is not a substitute for code validation. Question On macOS 14, is there a documented, supported guarantee that the connection-level EUID/ASID and the message-derived SecCode refer to the same process occurrence and the actual sender of this particular received request? The connection getters describe attributes captured when the connection was established, while SecCodeCreateWithXPCMessage derives a dynamic-code reference from the original received XPC dictionary. We do not assume that these APIs provide an atomic identity snapshot or prove that their observations refer to the same sender process instance. In particular, what are the limits of any such guarantee when messages or messaging capabilities are forwarded, a process calls exec, a process exits or is replaced, credentials or audit sessions change, or a connection is interrupted and re-established? What if the sender's state changes between message reception and completion of the validation sequence? Request for a supported alternative If this API sequence does not establish that correspondence, which public APIs available on macOS 14 can provide the effective UID, audit session ID, and dynamic-code identity from the same received-message provenance? We are not considering PID-only lookup, private audit-token access, or caller-supplied identity claims. A clarification that the requested guarantee is unavailable would also be valuable. References xpc_connection_get_euid xpc_connection_get_asid Apple DTS: Validating Signature Of XPC Process
Replies
0
Boosts
0
Views
51
Activity
5d
Supported completeness and lifecycle guarantees for es_new_descendants_client
Hello Apple Developer Technical Support, I am evaluating es_new_descendants_client for a local command runner that must report success only after its workload and every process descended from that workload have exited. If observation is incomplete or ambiguous, the runner must report failure. This is a design inquiry, not a report of a reproduced operating-system defect; no entitled prototype has been tested. The proposed observer would create its client and subscribe to lifecycle notifications before launching any workload. It would maintain a registry using process-lifetime identities, add processes on creation and remove them on exit. An unmatched event, missing required field, detected loss or observer failure would invalidate the run. It would consider closure only after all registered workload processes had exited. We have not established that these rules are sufficient. Could you clarify which of the following properties are supported API guarantees, and identify any that applications must not rely on? A documented reference or an explicit statement that a guarantee is unavailable would both help. Please identify applicable macOS/SDK versions and any known version-dependent limitations. 1. Membership and creation-event coverage Does the observed subtree retain a process and all of its future descendants after its original parent exits, it is reparented, it double-forks, or it changes process group/session with setpgid or setsid? Could a process remain observable for exit while creation events for its children become invisible? For a workload launched after successful subscription, does every successful process-creation path—including fork, vfork and posix_spawn—produce a lifecycle event sufficient to register the new process before closure can be declared? Which event and identity fields should be used for each path, including a child that exits without a successful exec? Does the calling observer receive the necessary event for its own initial workload launch? 2. Ordering and the meaning of exit Is there a supported per-client ordering guarantee that every child-creation event from a process is delivered before that process's exit notification, including concurrent creation and exit? Can the child's events arrive before the event that introduces that child? Please distinguish kernel enqueue order, handler delivery order and any processing order the application must impose. At what lifecycle boundary is ES_EVENT_TYPE_NOTIFY_EXIT generated? Does it establish that the identified process can no longer execute or initiate writes, or can relevant activity continue after the notification? We would not equate process exit with filesystem durability or completion of work already delegated to other processes. 3. Muting and other visibility filters Does a newly created descendants client have default process, path or target-path mutes that can suppress fork/exit notifications? What supported sequence of configuration and inspection calls establishes complete lifecycle visibility before launch, including mute inversion and executable-path changes? Apart from subscription and muting, are there policy, security, rate-limit or client-type exclusions that can suppress those events? Which suppressed events, if any, are intentionally absent from the sequence counter rather than reported as drops? 4. Sequence numbers and loss detection The global_seq_num documentation requires message version greater than 4. Is that field guaranteed for descendants-client lifecycle messages? Do notifications concerning the calling observer and its descendants use the same per-client sequence? How can a client establish a valid initial baseline and detect loss before its first received message? Is every dropped subscribed, unmuted lifecycle event reflected in the next delivered sequence number? What counter reset, wraparound or client-recreation rules must be handled? Would the proposed registry rule make terminal loss fail safely—for example, a lost final exit leaves a process registered—under the supported ordering and visibility semantics? Or is there a counterexample in which the registry can become empty while an unobserved descendant survives? 5. Synchronization, observer failure and delegated work Does es_sync_client provide any loss/completeness information beyond draining preceding queued messages? Its documented callbacks also run for a destroyed or null client, so we would not interpret callback arrival alone as successful completion. Is there a supported mechanism to distinguish a healthy drain from invalidation? What does “instigates” cover for this client? In particular, can it observe or attribute work executed by existing launchd/XPC services, or by unrelated processes receiving file descriptors? We would treat such work as outside a lineage-only closure claim unless it is explicitly covered or independently excluded. Does this client provide any supported protection against a same-UID workload stopping, killing or otherwise interfering with its observer, or must that isolation be supplied separately? Observer failure would invalidate the run; we are not assuming ES supplies a write barrier for evidence files. 6. Supported cleanup and deployment Is there a supported public mechanism to signal a non-child descendant by process-lifetime identity, without a PID-reuse race between observing it and sending a signal? Is there a recommended approach if the observer cannot wait on that process? We do not want to depend on private libproc functions as an application contract. Finally, is this use case eligible for com.apple.developer.endpoint-security.client in a standalone signed command-line observer, and what supported signing/provisioning or packaging requirements apply? This is a request for guidance, not an entitlement application. Our central question is whether supported APIs can establish complete descendant-process closure under these constraints. If they cannot, we would appreciate a clear statement of that limitation or a supported alternative. Thank you. Documentation consulted: es_new_descendants_client es_sync_client global_seq_num es_process_t
Replies
6
Boosts
0
Views
789
Activity
1w
Could not set environment: 150: Operation not permitted while System Integrity Protection is engaged
Hi. After the recent update of Ventura to 13.4 and Big Sur to 11.7.7 all of a sudden "launchctl setenv" returns the following errors. Could not set environment: 150: Operation not permitted while System Integrity Protection is engaged Is there any workaround to fix this?
Replies
7
Boosts
0
Views
5.3k
Activity
1w
XPCSession.cancel does not immediately cancel
I'm using an XPCSession to send a message to a service/agent. When calling session.cancel(reason: "stop") the connection is not immediately canceled. The session seems to wait for any pending replies from the service. According to the docs for XPCSession.cancel: When you cancel a session, it discards any unsent messages and invalidates its connection. If there are messages awaiting replies, the session calls the reply handlers with an appropriate XPCRichError. This does seem to imply that messages waiting for replies are immediately canceled, however that's not the case. The service may be busy and may take a while to respond, or it may not reply at all. The session is only canceled after all enqueued messages get a reply from the service. let session = try XPCSession(xpcService: "com.example.listener", cancellationHandler: { print("client session canceled") }) try session.send("Test", replyHandler: { reply in print("reply", reply) }) print("cancel") session.cancel(reason: "cancel") // calls cancellationHandler *after* receiving reply Is that expected behaviour? If the service does not respond at all the XPCService will never be canceled. Compared to xpc_connection_create + xpc_connection_cancel(connection) this does seem to immediately cancel the connection and call the reply_handler and event_handler. This does not wait for pending replies from the service. Is there an alternative way to force cancel an XPCSession? Main goal is to protect against two potential issues: The service is busy and doesn't respond in time. The client fires a timeout and wants to disconnect/reconnect, but the cancellationHandler is not called until service responds. So the timeout is not useful, client needs to wait for a reply anyway. The service does not respond at all. This could for example happen if a Launch Agent is improperly configured. The mach service is registered, but the agent may not launch. Sending a message on the XPCSession will never receive a reply.
Replies
3
Boosts
0
Views
148
Activity
1w
Sandboxed helper keeps running after the app is turned off in Background App Activity
Short version: we run a sandboxed helper as a hidden service account, started at boot by an SMAppService daemon. It works, even before login. But when the user turns our app off in Background App Activity, only the daemon stops. The helper keeps running. Is this setup supported, and what's the right way to manage the helper? What we want A Developer ID signed, notarized app (not Mac App Store) with a helper that parses untrusted input. The helper should: run as a dedicated, hidden, non-login local account; use App Sandbox, with its own container; be available before anyone logs in (after FileVault unlock). What we built An unsandboxed root LaunchDaemon, registered with SMAppService.daemon, runs this at boot: launchctl bootstrap user/<serviceUID> <fixed-agent-plist> The agent plist uses LimitLoadToSessionType=Background. The helper is a nested app in the same bundle, with com.apple.security.app-sandbox=true. We don't create a GUI session, change UID after the sandbox starts, or use private APIs. What we measured macOS 27.0 (26A428), arm64, dummy data only: Register and approve: the daemon starts. The helper starts as UID 60000, its container works, and reads outside it are denied. Turn the app off in Background App Activity: the daemon gets SIGTERM and stops. The helper keeps running (same PID). Turn it back on: the daemon starts again. Its bootstrap returns exit 5, because the old helper is still loaded. Call unregister(): the daemon stops. The helper keeps running. Cold boot (tested with a plain /Library/LaunchDaemons job, not yet SMAppService): the helper started and worked before login finished. For comparison, running the same sandboxed helper as a system daemon with UserName set to this account fails before main: Incoming message euid:60000 does not match secinitd uid:0. Questions Is this setup supported for shipping, including the sandbox starting before anyone logs in? Does the approval for daemon-bundled helpers cover a helper bootstrapped into another account's domain? Our plan: when the daemon gets SIGTERM, it runs bootout on the helper and its domain, and it treats bootstrap exit 5 as "already loaded". Is that the intended pattern, or is there a supported way for the helper to follow the app's Background App Activity setting? If this setup isn't supported, what public mechanism gives a sandboxed helper its own non-root identity before login? I can share the plists, entitlements and logs from a minimal reproducer.
Replies
6
Boosts
0
Views
402
Activity
1w
AlarmKit custom LiveActivityIntent: can executions overlap or be redelivered across app relaunch?
Hello, I'm developing an iPhone alarm app with AlarmKit. The alert has a custom secondary button whose intent conforms to LiveActivityIntent, declares supportedModes: .background and authenticationPolicy: .alwaysAllowed, and passes an alarm ID to app code from a @MainActor perform() implementation. The intent lives in the app target. It is not shared with a widget or an App Intents extension. The operation persists an in-progress record, awaits scheduling a new alarm, cancels the original only after scheduling succeeds, and then persists completion. After an interruption or relaunch, recovery reads the persisted original and candidate IDs and checks the system's alarm inventory. I want to understand which execution guarantees the app can rely on, so that recovery never schedules a duplicate alarm or cancels a valid candidate. I've read the LiveActivityIntent and App Intents runtime documentation. I understand how execution placement and foreground/background modes are described, but I couldn't find a public guarantee about overlap or redelivery when the app process is replaced. To be clear, I have not observed two simultaneous processes or duplicate execution in this setup. This is a question about what the app may assume, not a bug report. Questions For this app-target LiveActivityIntent configuration on iOS/iPadOS 26.x, can an older process of the same app still be executing an alarm-button intent while a newly launched process begins another invocation? Is there a documented single-process or handover guarantee an app may rely on? I'd appreciate it if the answer could distinguish multiple concurrent invocations within one process from overlap between an old and a newly launched process. Can the same alarm-button action be redelivered after an interruption or relaunch, including after perform() has thrown or returned? Which serialization or at-most-once guarantees, if any, apply to invocations for the same alarm ID, and which duplicate-delivery defenses must the app provide? I'm not assuming that every invocation comes from a new user tap. If the process that issued an AlarmKit scheduling or cancellation request terminates, may the app assume that the request has either completed or been abandoned before a newly launched process calls AlarmKit? If not, which public API checks or sequencing are recommended before recovery modifies the original or candidate alarm? I'm looking for supported app-level assumptions and recommended safeguards, not internal process lifecycle details. The app must preserve valid alarms and must never report an uncertain result as success. The shipping target is iPhone, with a minimum deployment target of 26.1. Earlier isolated testing on an iPad (9th generation, including iPadOS 26.7) did not show the overlap described above. Related question about the alert presentation after an intent error: [https://developer.apple.com/forums/thread/849075] Thank you!
Replies
0
Boosts
0
Views
311
Activity
2w
Supported macOS design for safely terminating an app-owned helper subtree?
I am designing a bounded local diagnostic helper for macOS. It would run only purpose-built helpers supplied by the application, not third-party or untrusted code. The design question is how to stop exactly those helpers and their descendants on timeout, without affecting an unrelated process or incorrectly reporting that cleanup is complete. This is a public-API suitability question, not a report of a reproduced macOS bug. The intended diagnostic is not an antivirus or endpoint-detection product. The required properties are: Identify each owned process by its lifetime and association with this helper run, not a numeric PID or process-group ID alone. Account for descendants across fork/exec, parent exit or reparenting, and process-group/session changes. Observing that a descendant escaped is not equivalent to preventing an escape. Terminate only the still-owned processes without a stale-identity race between checking ownership and signaling. Report completion only when all owned descendants have stopped and no new owned descendants can appear. Leader exit, IPC disconnection, or an unauthenticated empty process list would not be sufficient. Lost events or uncertain membership must leave the outcome inconclusive. Which supported public API or service/containment architecture can provide these properties? If they cannot all be guaranteed, which constraint should be changed and what guarantee can the supported alternative actually provide? I have reviewed the documentation for es_new_descendants_client and es_sync_client. The remaining questions are: Is a descendant-scoped Endpoint Security client appropriate for this non-security-product diagnostic? If so, which documented entitlement and packaging route applies? I am asking about eligibility, not assuming it. Does any supported design combine lifetime-safe control with containment of the whole owned subtree, including concurrent descendant creation? Merely receiving events would not establish that property. What additional protocol, if any, makes a synchronization callback sufficient to establish complete termination when client destruction, event loss, and concurrent activity are possible? I am not treating that callback alone as proof that no owned process remains. I can redesign around a helper that cannot create descendants if that is the supported approach. In that case, what supported mechanism enforces that restriction and what termination guarantees remain? So far, a standalone C harness has passed eleven fabricated-input cases with assertions enabled. It exercised no Endpoint Security client, process-tree creation/enumeration/control, or application behavior. It is not a runtime reproducer for this API-design question and does not establish native lifecycle safety. Pointers to documented guarantees, limitations, or an Apple sample would help me choose the architecture before preparing a narrowly scoped native test. I am not seeking private APIs or a way to disable platform protections. No logs, source archive, or binary is attached.
Replies
1
Boosts
0
Views
459
Activity
2w
Supported macOS confinement for a supervised process tree
I am evaluating a local diagnostic design before implementation or deployment and need to identify a public, supported macOS confinement mechanism. Proposed arrangement: A privileged custodian remains outside a separate privileged guardian's process group. The guardian launches a fixed diagnostic parent under a dedicated unprivileged identity. That parent sequentially launches three fixed sandboxed Python workloads, one child at a time. The current termination design targets the guardian's process group. It must not rely on whole-host process scans or indiscriminate killing. The proposed sandbox profiles are allow-default with file/network restrictions; the test-child profiles deny process-fork. We have not established that these restrictions prevent an existing process from changing its own group or session. Is there a public, supported interface or configuration that keeps all workload descendants within the supervisor's termination boundary from the initial child transition through final cleanup, while still allowing the parent to launch its authorized sequential children? In particular, please clarify: Escape through setsid/setpgid, spawn attributes, exec or native-library paths. When enforcement begins and whether descendants can relax it. Behavior when the diagnostic parent or guardian exits. Required privileges, entitlements, and supported OS/SDK versions. If the described sandbox categories do not establish that property, please identify the supported alternative boundary, if one exists. A different boundary would require an explicit design change on our side. I am requesting documented interface behavior and limitations—not private sandbox internals, a review of project code, or an absolute termination guarantee during kernel failure. No experiment has been performed to establish this property.
Replies
0
Boosts
0
Views
169
Activity
2w
Supported lifecycle and termination guarantees for an embedded macOS XPC service
We are evaluating a lifecycle architecture for a local macOS application and would appreciate guidance on supported public APIs. Proposed architecture: A normally signed, non-root host application. One embedded XPC service with exactly one intended client. No application-created subprocesses inside the service. No privileged helper, persistent LaunchAgent, exported endpoints, private APIs, or reduced system security. One bounded operation per session. Failed or interrupted operations must not automatically be retried. Initial validation would use synthetic workloads only. Our current evaluation target is macOS 15.6 on Apple silicon, using the macOS 15.5 SDK. Please identify any relevant deployment-version limitations. The XPC overview (https://developer.apple.com/documentation/xpc) describes an embedded service as tied to its client's lifetime. We also understand that xpc_connection_cancel (https://developer.apple.com/documentation/xpc/xpc_connection_cancel(_:)) is asynchronous and non-preemptive; we are not treating connection cancellation as proof of service termination. We need clarification on these points: Client death and service startup Does the documented client-lifetime relationship cover client termination, including SIGKILL, during service startup before the first reply? Does it also cover an already running service that is blocked or stopped with SIGSTOP? Which behavior is guaranteed, and which timing or failure cases are intentionally unspecified? Timeout while the client remains alive What supported public mechanism should a normal application use to terminate its own unresponsive embedded service when an operation exceeds its deadline? We want to avoid PID enumeration, PID-reuse races, broad process-group signaling, and exporting a full task-control port. Is there a supported identity-bound termination mechanism? If not, what architecture does Apple recommend? A stopped or hung client remains alive, so we do not assume client-lifetime coupling handles that separate failure case. Observing termination Which public notification reliably identifies the exit of the particular service instance, as distinct from connection invalidation or a missing reply? Because launchd is the parent, the application cannot simply waitpid the service. Is reaping entirely launchd's responsibility, and what completion claim can the application legitimately make? Identity and required privileges Which public signing requirements, launch constraints, sandbox settings, or entitlements are necessary for this architecture? Please distinguish authentication before accepting work from constraints enforced before service code executes. We do not assume peer authentication also grants termination rights. Restart behavior After interruption, cancellation, client exit, or service failure, under what circumstances can launchd or subsequent XPC activity start a replacement service? What supported pattern prevents accidental resubmission or resumption of the same failed operation? We are not asking for hard real-time guarantees during kernel failure, or claiming that forced termination proves callback completion or explicit memory zeroization. If this combination of requirements is unsupported, identifying that boundary and the smallest supported architectural alternative would be a useful answer. Documentation references or a minimal public sample would be welcome.
Replies
3
Boosts
0
Views
254
Activity
2w
macOS 27 - my faceless bg-only app now appears in the Dock - how to get rid of that?
My macOS app Find Any File contains another app inside its Resources folder. It's a background-only app that checks if the user presses a hotkey, in which case it launches my app. Since macOS 27, when the hotkey app is running, it appears in the Dock with a "Running in Background" subtitle. That's totally not wanted. How do I make it not appear in the Dock? I've got both "LSBackgroundOnly" and "LSUIElement" set to true in the Info.plist, to no avail.
Replies
3
Boosts
0
Views
268
Activity
3w
[27.0beta] Wrong app shown as running in Background in Dock
I develop a tool on macOS which is composed of an UI app to manage the main app settings, and an Agent that runs in background doing some tasks ? (Running the agent is optional, can be launched from the UI app, and can be launched by macOS at startup with SMAppService. ) Agent has the LSUIElement flag set, and only shows a Menu Extra (or whatever it now named), and sometimes some notifications. The whole App package is bundled this way MainAppUI.app/Contents/Library/LoginItems/AppAgent.app (for SMAppService to work) This has been working correctly for years Now on macOS 27 beta, once I quit the UI App, having launched the Agent, the Dock reports the UI App is still running in background (with the grey dot) . But only the Agent is running, not the UI app process. Moreover, System Settings->Background apps reports both the UI app AND the Agent as both requesting to run in background. I would have expected only the Agent being listed in System Settings, and nothing appearing in the Dock. Is this a bug in the OS beta , showing the top-level container bundle as the app running in background instead of the executable direct container ? Or maybe it's on me and I should bundle my app differently ? (I cannot "reverse" the bundle and put the Agent as the main app, with UI "inside", as double clicking the main app should launch the UI App , not the Agent. ) BTW, filed FB23203848 for the same subject. thanks for any direction
Replies
3
Boosts
1
Views
1.1k
Activity
3w
Crashe__CFRunLoopServiceMachPort.cold 96% Foreground
Hello, we have encountered a large number of __CFRunLoopServiceMachPort.cold crashes on iOS 26. These crashes frequently occur when the app transitions from the background to the foreground or is launched after sitting idle for a period of time. Despite extensive analysis, we have been unable to find a solution. Currently, the crash data indicates that this issue is specific to iOS 26. We would greatly appreciate your assistance. Thank you very much! Hardware Model: iPhone18,1 OS Version: iPhone OS 26.5.2 (23F84) Release Type: User Baseband Version: 1.60.02 Crash Reporter Key: fda96a4036dcb83e124660e11b654c9484b81dae Incident Identifier: EF18C4DD-7624-42D0-BA72-F17BBC263B16 Time Awake Since Boot: 2900000 seconds Triggered by Thread: 0, Dispatch Queue: com.apple.main-thread Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001917d316c Termination Reason: Namespace SIGNAL, Code 5, Trace/BPT trap: 5 Terminating Process: exc handler [82210] Application Specific Information: (ipc/rcv) invalid name Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 CoreFoundation 0x1917d316c __CFRunLoopServiceMachPort.cold.1 + 64 1 CoreFoundation 0x19168a444 __CFRunLoopServiceMachPort + 416 2 CoreFoundation 0x191654310 __CFRunLoopRun + 1188 3 CoreFoundation 0x19165354c _CFRunLoopRunSpecificWithOptions + 532 4 GraphicsServices 0x236df7498 GSEventRunModal + 120 5 UIKitCore 0x19734c244 -[UIApplication _run] + 796 6 UIKitCore 0x1972b7158 UIApplicationMain + 332 7 KMMVideo 0x1047fe24c 0x104304000 + 5218892 8 dyld 0x18e261c1c start + 6928 Thread 1 name: transmit_hls_7683_193735 Thread 1: 0 libsystem_kernel.dylib 0x2407da5e8 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x1f0852b48 _pthread_cond_wait + 980 2 libc++.1.dylib 0x1a0d5dbcc std::__1::condition_variable::wait(std::__1::unique_lockstd::__1::mutex&) + 32 3 iOSPlayer 0x118cd6114 a_task_runner::worker() + 116 4 iOSPlayer 0x118cd5650 a_task_runner::work_thread() + 196 5 iOSPlayer 0x118cd654c void* std::__1::__thread_proxy[abi:ne200100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_deletestd::__1::__thread_struct>, void (a_task_runner::)(), a_task_runner>>(void*) + 72 6 libsystem_pthread.dylib 0x1f0854438 _pthread_start + 136 7 libsystem_pthread.dylib 0x1f08508cc thread_start + 8 Thread 2: 0 libsystem_kernel.dylib 0x2407d9ed8 read + 8 1 XLTranscodeKit 0x115bb5f4c runtime.read_trampoline.abi0 + 28 Thread 3: Thread 4: 0 libsystem_kernel.dylib 0x2407da5e8 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x1f0852b48 _pthread_cond_wait + 980 2 XLTranscodeKit 0x115bb6648 runtime.pthread_cond_wait_trampoline.abi0 + 24 3 XLTranscodeKit 0x115bb4fb8 runtime.asmcgocall.abi0 + 200 4 ??? 0xd65f03c0 ??? Thread 5: 0 XLTranscodeKit 0x115b3eb68 */bytealg.IndexByteString + 40 1 XLTranscodeKit 0x115b966b8 runtime.findnull + 104 Thread 6: 0 libsystem_kernel.dylib 0x2407db8dc kevent + 8 1 XLTranscodeKit 0x115bb6398 runtime.kevent_trampoline.abi0 + 40 Thread 7: 0 libsystem_kernel.dylib 0x2407da5e8 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x1f0852b48 _pthread_cond_wait + 980 2 XLTranscodeKit 0x115bb6648 runtime.pthread_cond_wait_trampoline.abi0 + 24 3 XLTranscodeKit 0x115bb4fb8 runtime.asmcgocall.abi0 + 200 4 ??? 0xd65f03c0 ???
Replies
3
Boosts
0
Views
469
Activity
3w
Can an ExtensionFoundation-based extension on macOS have its own extension point and host its own extensions?
It is possible for an extension to an app (based on ExtensionFoundation) to declare its own extension point and host its own ExtensionFoundation extensions? Based on the documentation, I am guessing the answer is no, but worth double-checking. What would be the reason to prevent this? Every ExtensionFoundation extension runs in its own process, and may have need to be extended safely just as its host app does. Thank you!
Replies
3
Boosts
0
Views
332
Activity
3w