Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RDK-50163 Support for running Android containers #327

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ option(PLUGIN_STORAGE "Include Storage plugin" ON)
option(PLUGIN_MINIDUMP "Include Minidump plugin" ON)
option(PLUGIN_THUNDER "Include Thunder plugin" ON)
option(PLUGIN_OOMCRASH "Include OOMCrash plugin" ON)
option(PLUGIN_ANDROIDRUNTIME "Include Android plugin" ON)

# Optional RDK plugins
option(PLUGIN_TESTPLUGIN "Include TestPlugin plugin" OFF)
Expand Down Expand Up @@ -373,6 +374,10 @@ if(PLUGIN_GAMEPAD)
add_subdirectory(rdkPlugins/Gamepad)
endif()

if(PLUGIN_ANDROIDRUNTIME)
add_subdirectory(rdkPlugins/AndroidRuntime)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the rdkPlugins/AndroidRuntime directory in this PR

endif()

# Export targets in Dobby package
# ---------------------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions bundle/lib/include/DobbyRootfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class DobbyRootfs
std::string mPath;
int mDirFd;
bool mPersist;
bool androidRootfs;
};


Expand Down
8 changes: 8 additions & 0 deletions bundle/lib/include/DobbySpecConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ class DobbySpecConfig : public DobbyConfig
} MountPoint;
std::vector<MountPoint> mountPoints() const;

public:
bool androidEnabled() const;

public:
const std::string& rootfsPath() const override;

Expand Down Expand Up @@ -143,6 +146,7 @@ class DobbySpecConfig : public DobbyConfig
JSON_FIELD_PROCESSOR(processDevices);
JSON_FIELD_PROCESSOR(processCapabilities);
JSON_FIELD_PROCESSOR(processSeccomp);
JSON_FIELD_PROCESSOR(processAndroid);

#undef JSON_FIELD_PROCESSOR

Expand Down Expand Up @@ -180,6 +184,7 @@ class DobbySpecConfig : public DobbyConfig
const std::shared_ptr<IDobbyUtils> mUtilities;
const std::shared_ptr<const IDobbySettings::HardwareAccessSettings> mGpuSettings;
const std::shared_ptr<const IDobbySettings::HardwareAccessSettings> mVpuSettings;
const std::shared_ptr<const IDobbySettings::AndroidAccessSettings> mAndroidSettings;
const std::vector<std::string> mDefaultPlugins;
const Json::Value mRdkPluginsData;

Expand Down Expand Up @@ -230,6 +235,9 @@ class DobbySpecConfig : public DobbyConfig
std::string mEtcGroup;
std::string mEtcLdSoPreload;

private:
bool mAndroidEnabled;

private:
static int mNumCores;

Expand Down
49 changes: 42 additions & 7 deletions bundle/lib/source/DobbyRootfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ DobbyRootfs::DobbyRootfs(const std::shared_ptr<IDobbyUtils>& utils,
, mBundle(bundle)
, mDirFd(-1)
, mPersist(false)
, androidRootfs(false)
{
AI_LOG_FN_ENTRY();

Expand All @@ -72,6 +73,12 @@ DobbyRootfs::DobbyRootfs(const std::shared_ptr<IDobbyUtils>& utils,
return;
}

if (config->androidEnabled())
{
AI_LOG_WARN("Android container, using Android rootfs");
androidRootfs = true;
}

// try and open the new directory
mDirFd = openat(bundle->dirFd(), dirName.c_str(), O_CLOEXEC | O_DIRECTORY);
if (mDirFd < 0)
Expand All @@ -82,14 +89,41 @@ DobbyRootfs::DobbyRootfs(const std::shared_ptr<IDobbyUtils>& utils,
return;
}

// and finally construct the rootfs contents based on the config
if (!constructRootfs(mDirFd, config))
if (!androidRootfs)
{
AI_LOG_ERROR_EXIT("failed to construct bundle rootfs");
cleanUp();
return;
if (!constructRootfs(mDirFd, config))
{
AI_LOG_ERROR_EXIT("failed to construct bundle rootfs");
cleanUp();
return;
}
}
else
{
if (!createStandardMountPoints(mDirFd))
{
AI_LOG_ERROR("Failed to create standard mount points");
cleanUp();
return;
}

// process any extra mounts added by the client
const std::vector<DobbySpecConfig::MountPoint> extraMounts = config->mountPoints();
for (const DobbySpecConfig::MountPoint &mountPoint : extraMounts)
{
AI_LOG_DEBUG("attempting to create mount point '%s' %s",
mountPoint.destination.c_str(),
(mountPoint.type == DobbySpecConfig::MountPoint::Directory) ?
"directory" : "file");

if (!createMountPoint(mDirFd, mountPoint.destination,
(mountPoint.type == DobbySpecConfig::MountPoint::Directory)))
{
AI_LOG_FN_EXIT();
return;
}
}
}
// store the complete path
mPath = bundle->path() + "/" + dirName + "/";

Expand All @@ -113,6 +147,7 @@ DobbyRootfs::DobbyRootfs(const std::shared_ptr<IDobbyUtils>& utils,
, mBundle(bundle)
, mDirFd(-1)
, mPersist(false)
, androidRootfs(false)
{
AI_LOG_FN_ENTRY();

Expand Down Expand Up @@ -282,7 +317,7 @@ void DobbyRootfs::cleanUp()

if (mDirFd >= 0)
{
if (!mPersist)
if (!mPersist && !androidRootfs)
{
if (!mUtilities->rmdirContents(mDirFd))
{
Expand All @@ -296,7 +331,7 @@ void DobbyRootfs::cleanUp()
}

// the rootfs directory should now be empty, so can now delete it
if (!mPath.empty() && (rmdir(mPath.c_str()) != 0))
if (!androidRootfs && !mPath.empty() && (rmdir(mPath.c_str()) != 0))
{
AI_LOG_SYS_ERROR(errno, "failed to delete rootfs dir");
}
Expand Down
141 changes: 138 additions & 3 deletions bundle/lib/source/DobbySpecConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ static const ctemplate::StaticTemplateString USERNS_ENABLED =
static const ctemplate::StaticTemplateString USERNS_DISABLED =
STS_INIT(USERNS_DISABLED, "USERNS_DISABLED");

static const ctemplate::StaticTemplateString ANDROID_ENABLED =
STS_INIT(ANDROID_ENABLED, "ANDROID_ENABLED");
static const ctemplate::StaticTemplateString ANDROID_DISABLED =
STS_INIT(ANDROID_DISABLED, "ANDROID_DISABLED");

static const ctemplate::StaticTemplateString MEM_LIMIT =
STS_INIT(MEM_LIMIT, "MEM_LIMIT");

Expand Down Expand Up @@ -187,15 +192,31 @@ static const ctemplate::StaticTemplateString SECCOMP_SYSCALLS =
#define JSON_FLAG_FILECAPABILITIES (0x1U << 20)
#define JSON_FLAG_VPU (0x1U << 21)
#define JSON_FLAG_SECCOMP (0x1U << 22)
#define JSON_FLAG_ANDROID (0x1U << 23)

int DobbySpecConfig::mNumCores = -1;

// TODO: should we only allowed these if a network namespace is enabled ?
const std::map<std::string, int> DobbySpecConfig::mAllowedCaps =
{
{ "CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL },
{ "CAP_CHOWN", CAP_CHOWN },
{ "CAP_DAC_OVERRIDE", CAP_DAC_OVERRIDE },
{ "CAP_DAC_READ_SEARCH", CAP_DAC_READ_SEARCH },
{ "CAP_FOWNER", CAP_FOWNER },
{ "CAP_KILL", CAP_KILL },
{ "CAP_MKNOD", CAP_MKNOD },
{ "CAP_NET_ADMIN", CAP_NET_ADMIN },
{ "CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE },
{ "CAP_NET_BROADCAST", CAP_NET_BROADCAST },
{ "CAP_NET_RAW", CAP_NET_RAW },
{ "CAP_SETGID", CAP_SETGID },
{ "CAP_SETPCAP", CAP_SETPCAP },
{ "CAP_SETUID", CAP_SETUID },
{ "CAP_SYSLOG", CAP_SYSLOG },
{ "CAP_SYS_ADMIN", CAP_SYS_ADMIN },
{ "CAP_SYS_PTRACE", CAP_SYS_PTRACE },
{ "CAP_SYS_RESOURCE", CAP_SYS_RESOURCE }
};

// -----------------------------------------------------------------------------
Expand All @@ -216,6 +237,7 @@ DobbySpecConfig::DobbySpecConfig(const std::shared_ptr<IDobbyUtils> &utils,
: mUtilities(utils)
, mGpuSettings(settings->gpuAccessSettings())
, mVpuSettings(settings->vpuAccessSettings())
, mAndroidSettings(settings->androidAccessSettings())
, mDefaultPlugins(settings->defaultPlugins())
, mRdkPluginsData(settings->rdkPluginsData())
, mDictionary(nullptr)
Expand All @@ -229,6 +251,7 @@ DobbySpecConfig::DobbySpecConfig(const std::shared_ptr<IDobbyUtils> &utils,
, mDebugDbus(IDobbyIPCUtils::BusType::NoneBus)
, mConsoleDisabled(true)
, mConsoleLimit(-1)
, mAndroidEnabled(false)
, mRootfsPath("rootfs")
{
// get the number of (online) cpu cores on the system if we haven't already
Expand Down Expand Up @@ -296,6 +319,7 @@ DobbySpecConfig::DobbySpecConfig(const std::shared_ptr<IDobbyUtils> &utils,
: mUtilities(utils)
, mGpuSettings(settings->gpuAccessSettings())
, mVpuSettings(settings->vpuAccessSettings())
, mAndroidSettings(settings->androidAccessSettings())
, mDictionary(nullptr)
, mConf(nullptr)
, mSpecVersion(SpecVersion::Unknown)
Expand Down Expand Up @@ -405,6 +429,11 @@ const std::string& DobbySpecConfig::consolePath() const
return mConsolePath;
}

bool DobbySpecConfig::androidEnabled() const
{
return mAndroidEnabled;
}

const std::map<std::string, Json::Value>& DobbySpecConfig::legacyPlugins() const
{
return mLegacyPlugins;
Expand Down Expand Up @@ -479,6 +508,7 @@ bool DobbySpecConfig::parseSpec(ctemplate::TemplateDictionary* dictionary,

static const ProcessorMap processors =
{
{ "android", { JSON_FLAG_ANDROID, &DobbySpecConfig::processAndroid } }, /* NOTE: process android before user */
{ "env", { JSON_FLAG_ENV, &DobbySpecConfig::processEnv } },
{ "args", { JSON_FLAG_ARGS, &DobbySpecConfig::processArgs } },
{ "cwd", { JSON_FLAG_CWD, &DobbySpecConfig::processCwd } },
Expand Down Expand Up @@ -627,6 +657,11 @@ bool DobbySpecConfig::parseSpec(ctemplate::TemplateDictionary* dictionary,
dictionary->SetValue(NO_NEW_PRIVS, "true");
}

if (!(flags & JSON_FLAG_ANDROID))
{
dictionary->ShowSection(ANDROID_DISABLED);
}

// step 6 - enable the RDK plugins section
dictionary->ShowSection(ENABLE_RDK_PLUGINS);

Expand Down Expand Up @@ -829,9 +864,10 @@ bool DobbySpecConfig::processUser(const Json::Value& value,
mUserId = uid.asUInt();
mGroupId = gid.asUInt();


// sanity check the uid and gid are valid, and make sure we aren't being
// asked to start the container as root
if (mUserId == 0)
// asked to start the container as root unless it is Android
if ((mUserId == 0) && (!mAndroidEnabled))
{
AI_LOG_ERROR("the user.uid cannot be root (0)");
return false;
Expand All @@ -841,13 +877,112 @@ bool DobbySpecConfig::processUser(const Json::Value& value,
AI_LOG_ERROR("invalid uid or gid field, values must be less than 65535");
return false;
}

dictionary->SetIntValue(USER_ID, mUserId);
dictionary->SetIntValue(GROUP_ID, mGroupId);

return true;
}

// -----------------------------------------------------------------------------
/**
* @brief Processes the android field of the json spec
*
* Example json:
*
* "android": true
* "android": false
*
* This field controls whether to enable android customisations or not.
*
* @param[in] value The json spec document from the client
* @param[in] dictionary Pointer to the OCI dictionary to populate
*
* @return true if correctly processed the value, otherwise false.
*/
bool DobbySpecConfig::processAndroid(const Json::Value& value,
ctemplate::TemplateDictionary* dictionary)
{
bool enabled;
mAndroidEnabled = false;
if (value.isBool())
{
enabled = value.asBool();
}
else if (value.isNull())
{
enabled = false;
}
else
{
AI_LOG_ERROR("invalid android field");
return false;
}

mAndroidEnabled = enabled;

AI_LOG_INFO("Android is %s", enabled ? "enabled" : "disabled");

dictionary->ShowSection(enabled ? ANDROID_ENABLED : ANDROID_DISABLED);

if(!enabled) // No need for extra settings if Android disabled
{
return true;
}

// add any extra mounts (ie ipc sockets, shared memory files, etc)
for (const auto& extraMount : mAndroidSettings->extraMounts)
{
ctemplate::TemplateDictionary *subDict = dictionary->AddSectionDictionary(MOUNT_SECTION);
subDict->SetValue(MOUNT_SRC, extraMount.source);
subDict->SetValue(MOUNT_DST, extraMount.target);
subDict->SetValue(MOUNT_TYPE, extraMount.type);

for (const std::string& flag : extraMount.flags)
{
ctemplate::TemplateDictionary *optSubDict = subDict->AddSectionDictionary(MOUNT_OPT_SECTION);
optSubDict->SetValue(MOUNT_OPT, flag);
}

// store the mount point for rootfs construction
storeMountPoint(extraMount.type, extraMount.source, extraMount.target);
}

// device nodes should be static, so get the details once and store for
// all subsequent calls
static std::mutex scanningLock;
static std::atomic<bool> scannedDevNodes(false);
static std::list<DobbyConfig::DevNode> devNodes;

if (!scannedDevNodes)
{
std::lock_guard<std::mutex> locker(scanningLock);

if (!scannedDevNodes)
{
for (const auto& devNode : mAndroidSettings->deviceNodes)
{
devNodes.emplace_back(DevNode{ devNode.path,
devNode.major,
devNode.minor,
devNode.filemode });
}
scannedDevNodes = true;
}
}

// add to the additional device node section
for (const DobbyConfig::DevNode &devNode : devNodes)
{
ctemplate::TemplateDictionary *subDict = dictionary->AddSectionDictionary(ADDITIONAL_DEVICE_NODES);
subDict->SetValue(DEVICE_PATH, devNode.path);
subDict->SetIntValue(DEVICE_MAJOR, devNode.major);
subDict->SetIntValue(DEVICE_MINOR, devNode.minor);
subDict->SetIntValue(DEVICE_FILE_MODE, devNode.mode);
}

return true;
}

// -----------------------------------------------------------------------------
/**
* @brief Processes the userNs field of the json spec
Expand Down