Skip to content

Commit c5c35c1

Browse files
authored
Merge pull request #2228 from drodriguez/android-process
[android] Implement Process and modify TestProcess to pass.
2 parents 4b272f3 + 79019d2 commit c5c35c1

File tree

4 files changed

+445
-36
lines changed

4 files changed

+445
-36
lines changed

CoreFoundation/Base.subproj/CFPlatform.c

Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,4 +1546,374 @@ CF_CROSS_PLATFORM_EXPORT void *_CFReallocf(void *ptr, size_t size) {
15461546
#endif
15471547
}
15481548

1549+
#if TARGET_OS_ANDROID
1550+
1551+
#include <dlfcn.h>
1552+
#include <spawn.h>
1553+
1554+
// Android doesn't provide posix_spawn APIs until recent API level, so we cannot
1555+
// depend on them, but we can imitate the API, and perform the same work.
1556+
1557+
static pthread_once_t posixSpawnOnce = PTHREAD_ONCE_INIT;
1558+
static _CFPosixSpawnFileActionsRef (*_CFPosixSpawnFileActionsAllocImpl)(void);
1559+
static int (*_CFPosixSpawnFileActionsInitImpl)(_CFPosixSpawnFileActionsRef);
1560+
static int (*_CFPosixSpawnFileActionsDestroyImpl)(_CFPosixSpawnFileActionsRef);
1561+
static void (*_CFPosixSpawnFileActionsDeallocImpl)(_CFPosixSpawnFileActionsRef);
1562+
static int (*_CFPosixSpawnFileActionsAddDup2Impl)(_CFPosixSpawnFileActionsRef, int, int);
1563+
static int (*_CFPosixSpawnFileActionsAddCloseImpl)(_CFPosixSpawnFileActionsRef, int);
1564+
static int (*_CFPosixSpawnImpl)(pid_t *_CF_RESTRICT, const char *_CF_RESTRICT, _CFPosixSpawnFileActionsRef, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT, char *_Nullable const[_Nullable _CF_RESTRICT], char *_Nullable const[_Nullable _CF_RESTRICT]);
1565+
1566+
static _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAllocImplPost28() {
1567+
_CFPosixSpawnFileActionsRef actions = malloc(sizeof(posix_spawn_file_actions_t));
1568+
CFAssert(actions != NULL, __kCFLogAssertion, "malloc failed");
1569+
return actions;
1570+
}
1571+
1572+
static void _CFPosixSpawnFileActionsDeallocImplBoth(_CFPosixSpawnFileActionsRef file_actions) {
1573+
free(file_actions);
1574+
}
1575+
1576+
enum _CFPosixSpawnFileActionTypePre28 {
1577+
_CFPosixSpawnFileActionDup2Pre28,
1578+
_CFPosixSpawnFileActionClosePre28,
1579+
};
1580+
1581+
struct _CFPosixSpawnFileActionPre28 {
1582+
enum _CFPosixSpawnFileActionTypePre28 type;
1583+
union {
1584+
struct {
1585+
int filedes;
1586+
int newfiledes;
1587+
} dup2Action;
1588+
struct {
1589+
int filedes;
1590+
} closeAction;
1591+
};
1592+
};
1593+
1594+
struct _CFPosixSpawnFileActionsPre28 {
1595+
struct _CFPosixSpawnFileActionPre28 *actions;
1596+
size_t actionsCount;
1597+
size_t actionsCapacity;
1598+
int32_t isValid;
1599+
};
1600+
1601+
static const int32_t _CFPosixSpawnFileActionsPre28Valid = 0x600D600D;
1602+
1603+
static _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAllocImplPre28() {
1604+
_CFPosixSpawnFileActionsRef actions = calloc(1, sizeof(struct _CFPosixSpawnFileActionsPre28));
1605+
CFAssert(actions != NULL, __kCFLogAssertion, "malloc failed");
1606+
return actions;
1607+
}
1608+
1609+
static int _CFPosixSpawnFileActionsInitImplPre28(_CFPosixSpawnFileActionsRef file_actions) {
1610+
if (file_actions == NULL) {
1611+
return EINVAL;
1612+
}
1613+
1614+
struct _CFPosixSpawnFileActionsPre28 *actions = (struct _CFPosixSpawnFileActionsPre28 *)file_actions;
1615+
1616+
actions->actions = malloc(8 * sizeof(struct _CFPosixSpawnFileActionPre28));
1617+
if (actions->actions == NULL) {
1618+
return ENOMEM;
1619+
}
1620+
actions->actionsCount = 0;
1621+
actions->actionsCapacity = 8;
1622+
1623+
actions->isValid = _CFPosixSpawnFileActionsPre28Valid;
1624+
1625+
return 0;
1626+
}
1627+
1628+
static int _CFPosixSpawnFileActionsDestroyImplPre28(_CFPosixSpawnFileActionsRef file_actions) {
1629+
if (file_actions == NULL) {
1630+
return EINVAL;
1631+
}
1632+
1633+
struct _CFPosixSpawnFileActionsPre28 *actions = (struct _CFPosixSpawnFileActionsPre28 *)file_actions;
1634+
if (actions->isValid != _CFPosixSpawnFileActionsPre28Valid) {
1635+
return EINVAL;
1636+
}
1637+
1638+
free(actions->actions);
1639+
actions->actionsCount = 0;
1640+
actions->actionsCapacity = 0;
1641+
1642+
actions->isValid = 0;
1643+
1644+
return 0;
1645+
}
1646+
1647+
static int _CFPosixSpawnFileActionsAddDup2ImplPre28(_CFPosixSpawnFileActionsRef file_actions, int filedes, int newfiledes) {
1648+
if (file_actions == NULL) {
1649+
return EINVAL;
1650+
}
1651+
1652+
if (filedes < 0 || newfiledes < 0) {
1653+
return EBADF;
1654+
}
1655+
1656+
struct _CFPosixSpawnFileActionsPre28 *actions = (struct _CFPosixSpawnFileActionsPre28 *)file_actions;
1657+
if (actions->isValid != _CFPosixSpawnFileActionsPre28Valid) {
1658+
return EINVAL;
1659+
}
1660+
1661+
if (actions->actionsCount == actions->actionsCapacity) {
1662+
struct _CFPosixSpawnFileActionPre28 *newActions = realloc(actions->actions, actions->actionsCapacity * 2);
1663+
if (newActions == NULL) {
1664+
return ENOMEM;
1665+
}
1666+
actions->actions = newActions;
1667+
actions->actionsCapacity *= 2;
1668+
}
1669+
1670+
actions->actions[actions->actionsCount++] = (struct _CFPosixSpawnFileActionPre28) {
1671+
.type = _CFPosixSpawnFileActionDup2Pre28,
1672+
.dup2Action = {
1673+
.filedes = filedes,
1674+
.newfiledes = newfiledes
1675+
}
1676+
};
1677+
1678+
return 0;
1679+
}
1680+
1681+
static int _CFPosixSpawnFileActionsAddCloseImplPre28(_CFPosixSpawnFileActionsRef file_actions, int filedes) {
1682+
if (file_actions == NULL) {
1683+
return EINVAL;
1684+
}
1685+
1686+
if (filedes < 0) {
1687+
return EBADF;
1688+
}
1689+
1690+
struct _CFPosixSpawnFileActionsPre28 *actions = (struct _CFPosixSpawnFileActionsPre28 *)file_actions;
1691+
if (actions->isValid != _CFPosixSpawnFileActionsPre28Valid) {
1692+
return EINVAL;
1693+
}
1694+
1695+
if (actions->actionsCount == actions->actionsCapacity) {
1696+
struct _CFPosixSpawnFileActionPre28 *newActions = realloc(actions->actions, actions->actionsCapacity * 2);
1697+
if (newActions == NULL) {
1698+
return ENOMEM;
1699+
}
1700+
actions->actions = newActions;
1701+
actions->actionsCapacity *= 2;
1702+
}
1703+
1704+
actions->actions[actions->actionsCount++] = (struct _CFPosixSpawnFileActionPre28) {
1705+
.type = _CFPosixSpawnFileActionClosePre28,
1706+
.closeAction = {
1707+
.filedes = filedes
1708+
}
1709+
};
1710+
1711+
return 0;
1712+
}
1713+
1714+
static int _CFPosixSpawnImplPre28(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT path, _CFPosixSpawnFileActionsRef file_actions, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp, char *_Nullable const argv[_Nullable _CF_RESTRICT], char *_Nullable const envp[_Nullable _CF_RESTRICT]) {
1715+
// TODO: We completely ignore attrp, because at the moment, the only
1716+
// invocation doesn't pass a value.
1717+
if (attrp != NULL) {
1718+
return EINVAL;
1719+
}
1720+
1721+
struct _CFPosixSpawnFileActionsPre28 *actions = (struct _CFPosixSpawnFileActionsPre28 *)file_actions;
1722+
if (actions != NULL && actions->isValid != _CFPosixSpawnFileActionsPre28Valid) {
1723+
return EINVAL;
1724+
}
1725+
1726+
// Block signals during this fork/execv dance.
1727+
sigset_t signalSet;
1728+
sigfillset(&signalSet);
1729+
sigset_t oldMask;
1730+
if (sigprocmask(SIG_BLOCK, &signalSet, &oldMask) != 0) {
1731+
CFAssert1(FALSE, __kCFLogAssertion, "sigprocmask() failed: %d", errno);
1732+
}
1733+
1734+
pid_t forkPid = fork();
1735+
if (forkPid != 0) {
1736+
// This is the parent. fork call might have been successful or not.
1737+
1738+
// Unblock signals.
1739+
if (sigprocmask(SIG_SETMASK, &oldMask, NULL) != 0) {
1740+
CFAssert1(FALSE, __kCFLogAssertion, "sigprocmask() failed: %d", errno);
1741+
}
1742+
1743+
if (forkPid < 0) {
1744+
return forkPid;
1745+
}
1746+
1747+
if (pid != NULL) {
1748+
*pid = forkPid;
1749+
}
1750+
1751+
return 0;
1752+
}
1753+
1754+
// This is the child.
1755+
1756+
// Clean up the parent signal handlers
1757+
for (int idx = 1; idx < NSIG; idx++) {
1758+
// Seems that SIGKILL/SIGSTOP are sometimes silently ignored, and
1759+
// sometimes return EINVAL. Since one cannot change the handlers anyway,
1760+
// skip them.
1761+
if (idx == SIGKILL || idx == SIGSTOP) {
1762+
continue;
1763+
}
1764+
1765+
struct sigaction sigAction;
1766+
if (sigaction(idx, NULL, &sigAction) != 0) {
1767+
exit(127);
1768+
}
1769+
1770+
if (sigAction.sa_handler != SIG_IGN) {
1771+
sigAction.sa_handler = SIG_DFL;
1772+
if (sigaction(idx, &sigAction, NULL) != 0) {
1773+
exit(127);
1774+
}
1775+
}
1776+
}
1777+
1778+
// Perform the actions
1779+
if (actions != NULL) {
1780+
for (size_t idx = 0; idx < actions->actionsCount; idx++) {
1781+
struct _CFPosixSpawnFileActionPre28 *action = &(actions->actions[idx]);
1782+
if (action->type == _CFPosixSpawnFileActionDup2Pre28) {
1783+
if (dup2(action->dup2Action.filedes, action->dup2Action.newfiledes) < 0) {
1784+
exit(127);
1785+
}
1786+
} else if (actions->actions[idx].type == _CFPosixSpawnFileActionClosePre28) {
1787+
if (close(action->closeAction.filedes) != 0) {
1788+
exit(127);
1789+
}
1790+
}
1791+
}
1792+
}
1793+
1794+
// Unblock the signals
1795+
if (sigprocmask(SIG_SETMASK, &oldMask, NULL) != 0) {
1796+
CFAssert1(FALSE, __kCFLogAssertion, "sigprocmask() failed: %d", errno);
1797+
}
1798+
1799+
// If execv fails, we will simply exit 127 as the standard says.
1800+
execve(path, argv, envp ?: environ);
1801+
exit(127);
1802+
// no need for return here
1803+
}
1804+
1805+
static void _CFPosixSpawnInitializeCallback() {
1806+
// Let's check if the posix_spawn is present.
1807+
(void)dlerror(); // Clean up the error.
1808+
_CFPosixSpawnImpl = (int (*)(pid_t *_CF_RESTRICT, const char *_CF_RESTRICT, void *, void *_CF_RESTRICT, char *const *_CF_RESTRICT, char *const *_CF_RESTRICT))dlsym(RTLD_DEFAULT, "posix_spawn");
1809+
char *dlsymError = dlerror();
1810+
CFAssert1(dlsymError == NULL, __kCFLogAssertion, "dlsym failed: %s", dlsymError);
1811+
if (_CFPosixSpawnImpl != NULL) {
1812+
// posix_spawn_fn is available, so use it
1813+
_CFPosixSpawnFileActionsAllocImpl = _CFPosixSpawnFileActionsAllocImplPost28;
1814+
_CFPosixSpawnFileActionsDeallocImpl = _CFPosixSpawnFileActionsDeallocImplBoth;
1815+
1816+
_CFPosixSpawnFileActionsInitImpl = (int (*)(void *))dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_init");
1817+
dlsymError = dlerror();
1818+
CFAssert1(_CFPosixSpawnFileActionsInitImpl != NULL, __kCFLogAssertion, "loading posix_spawn_file_actions_init failed: %s", dlsymError);
1819+
1820+
_CFPosixSpawnFileActionsDestroyImpl = (int (*)(void *))dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_destroy");
1821+
dlsymError = dlerror();
1822+
CFAssert1(_CFPosixSpawnFileActionsDestroyImpl != NULL, __kCFLogAssertion, "loading posix_spawn_file_actions_destroy failed: %s", dlsymError);
1823+
1824+
_CFPosixSpawnFileActionsAddDup2Impl = (int (*)(void *, int, int))dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_adddup2");
1825+
dlsymError = dlerror();
1826+
CFAssert1(_CFPosixSpawnFileActionsAddDup2Impl != NULL, __kCFLogAssertion, "loading posix_spawn_file_actions_adddup2 failed: %s", dlsymError);
1827+
1828+
_CFPosixSpawnFileActionsAddCloseImpl = (int (*)(void *, int))dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addclose");
1829+
dlsymError = dlerror();
1830+
CFAssert1(_CFPosixSpawnFileActionsAddCloseImpl != NULL, __kCFLogAssertion, "loading posix_spawn_file_actions_addclose failed: %s", dlsymError);
1831+
} else {
1832+
// posix_spawn_fn is not available, setup our workaround
1833+
_CFPosixSpawnFileActionsAllocImpl = _CFPosixSpawnFileActionsAllocImplPre28;
1834+
_CFPosixSpawnFileActionsDeallocImpl = _CFPosixSpawnFileActionsDeallocImplBoth;
1835+
_CFPosixSpawnFileActionsInitImpl = _CFPosixSpawnFileActionsInitImplPre28;
1836+
_CFPosixSpawnFileActionsDestroyImpl = _CFPosixSpawnFileActionsDestroyImplPre28;
1837+
_CFPosixSpawnFileActionsAddDup2Impl = _CFPosixSpawnFileActionsAddDup2ImplPre28;
1838+
_CFPosixSpawnFileActionsAddCloseImpl = _CFPosixSpawnFileActionsAddCloseImplPre28;
1839+
_CFPosixSpawnImpl = _CFPosixSpawnImplPre28;
1840+
}
1841+
}
1842+
1843+
static void _CFPosixSpawnInitialize() {
1844+
int r = pthread_once(&posixSpawnOnce, _CFPosixSpawnInitializeCallback);
1845+
CFAssert(r == 0, __kCFLogAssertion, "pthread_once failed");
1846+
}
1847+
1848+
CF_EXPORT _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAlloc() {
1849+
_CFPosixSpawnInitialize();
1850+
return _CFPosixSpawnFileActionsAllocImpl();
1851+
}
1852+
1853+
CF_EXPORT int _CFPosixSpawnFileActionsInit(_CFPosixSpawnFileActionsRef file_actions) {
1854+
_CFPosixSpawnInitialize();
1855+
return _CFPosixSpawnFileActionsInitImpl(file_actions);
1856+
}
1857+
1858+
CF_EXPORT int _CFPosixSpawnFileActionsDestroy(_CFPosixSpawnFileActionsRef file_actions) {
1859+
_CFPosixSpawnInitialize();
1860+
return _CFPosixSpawnFileActionsDestroyImpl(file_actions);
1861+
}
1862+
1863+
CF_EXPORT void _CFPosixSpawnFileActionsDealloc(_CFPosixSpawnFileActionsRef file_actions) {
1864+
_CFPosixSpawnInitialize();
1865+
_CFPosixSpawnFileActionsDeallocImpl(file_actions);
1866+
}
1867+
1868+
CF_EXPORT int _CFPosixSpawnFileActionsAddDup2(_CFPosixSpawnFileActionsRef file_actions, int filedes, int newfiledes) {
1869+
_CFPosixSpawnInitialize();
1870+
return _CFPosixSpawnFileActionsAddDup2Impl(file_actions, filedes, newfiledes);
1871+
}
1872+
1873+
CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_actions, int filedes) {
1874+
_CFPosixSpawnInitialize();
1875+
return _CFPosixSpawnFileActionsAddCloseImpl(file_actions, filedes);
1876+
}
1877+
1878+
CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT path, _CFPosixSpawnFileActionsRef file_actions, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp, char *_Nullable const argv[_Nullable _CF_RESTRICT], char *_Nullable const envp[_Nullable _CF_RESTRICT]) {
1879+
_CFPosixSpawnInitialize();
1880+
return _CFPosixSpawnImpl(pid, path, file_actions, attrp, argv, envp);
1881+
}
1882+
1883+
#elif !TARGET_OS_WIN32
1884+
1885+
#include <spawn.h>
1886+
1887+
CF_EXPORT _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAlloc() {
1888+
_CFPosixSpawnFileActionsRef actions = malloc(sizeof(posix_spawn_file_actions_t));
1889+
CFAssert(actions != NULL, __kCFLogAssertion, "malloc failed");
1890+
return actions;
1891+
}
1892+
1893+
CF_EXPORT int _CFPosixSpawnFileActionsInit(_CFPosixSpawnFileActionsRef file_actions) {
1894+
return posix_spawn_file_actions_init((posix_spawn_file_actions_t *)file_actions);
1895+
}
1896+
1897+
CF_EXPORT int _CFPosixSpawnFileActionsDestroy(_CFPosixSpawnFileActionsRef file_actions) {
1898+
return posix_spawn_file_actions_destroy((posix_spawn_file_actions_t *)file_actions);
1899+
}
1900+
1901+
CF_EXPORT void _CFPosixSpawnFileActionsDealloc(_CFPosixSpawnFileActionsRef file_actions) {
1902+
free(file_actions);
1903+
}
1904+
1905+
CF_EXPORT int _CFPosixSpawnFileActionsAddDup2(_CFPosixSpawnFileActionsRef file_actions, int filedes, int newfiledes) {
1906+
return posix_spawn_file_actions_adddup2((posix_spawn_file_actions_t *)file_actions, filedes, newfiledes);
1907+
}
1908+
1909+
CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_actions, int filedes) {
1910+
return posix_spawn_file_actions_addclose((posix_spawn_file_actions_t *)file_actions, filedes);
1911+
}
1912+
1913+
CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT path, _CFPosixSpawnFileActionsRef file_actions, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp, char *_Nullable const argv[_Nullable _CF_RESTRICT], char *_Nullable const envp[_Nullable _CF_RESTRICT]) {
1914+
return posix_spawn(pid, path, (posix_spawn_file_actions_t *)file_actions, (posix_spawnattr_t *)attrp, argv, envp);
1915+
}
1916+
1917+
#endif
1918+
15491919
#endif

0 commit comments

Comments
 (0)