Skip to content

Commit 56c25f1

Browse files
authored
Merge pull request anbox#1309 from morphis/binderfs-support
many: add support for binderfs
2 parents 0a49ae0 + 92286b8 commit 56c25f1

14 files changed

+332
-7
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ build*/
22
parts/
33
stage/
44
prime/
5+
snap/.snapcraft
56
android-images/
67
*.snap
78
CMakeLists.txt.user

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ if (ENABLE_MIR)
9292
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMIR_SUPPORT")
9393
endif()
9494

95+
if (NOT BINDERFS_PATH)
96+
set(BINDERFS_PATH "/dev/binderfs")
97+
endif()
98+
9599
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEGL_NO_X11")
96100

97101
if((Protobuf_VERSION VERSION_GREATER "3.7") OR (Protobuf_VERSION VERSION_EQUAL "3.7"))

scripts/container-manager.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ start() {
8585
EXTRA_ARGS="$EXTRA_ARGS --container-network-dns-servers=$container_network_dns"
8686
fi
8787

88+
# Load all relevant kernel modules
89+
modprobe binder_linux
90+
modprobe ashmem_linux
91+
92+
# Ensure we have binderfs mounted when our kernel supports it
93+
if cat /proc/filesystems | grep -q binder ; then
94+
mkdir -p "$SNAP_COMMON"/binderfs
95+
# Remove old mounts so that we start fresh without any devices allocated
96+
if cat /proc/mounts | grep -q "binder $SNAP_COMMON/binderfs" ; then
97+
umount "$SNAP_COMMON"/binderfs
98+
fi
99+
mount -t binder none "$SNAP_COMMON"/binderfs
100+
fi
101+
88102
exec "$SNAP"/bin/anbox-wrapper.sh container-manager \
89103
--data-path="$DATA_PATH" \
90104
--android-image="$ANDROID_IMG" \

scripts/snap-wrapper.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,10 @@ if [ "$(snapctl get touch-emulation.enable)" = false ]; then
4747
export ANBOX_ENABLE_TOUCH_EMULATION=false
4848
fi
4949

50-
exec "$SNAP"/usr/bin/anbox "$@"
50+
# Use custom Anbox binary for debugging purposes if available
51+
ANBOX="$SNAP"/usr/bin/anbox
52+
if [ -e "$SNAP_COMMON"/anbox.debug ]; then
53+
ANBOX="$SNAP_COMMON"/anbox.debug
54+
fi
55+
56+
exec "$ANBOX" "$@"

snap/snapcraft.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ parts:
257257
# that is fixed we can avoid using a prefix here.
258258
- -DCMAKE_INSTALL_PREFIX:PATH=/usr
259259
- -DANBOX_VERSION=$SNAPCRAFT_PROJECT_VERSION
260+
- -DBINDERFS_PATH=/var/snap/anbox/common/binderfs
260261
# FIXME: Once we have everything in place for full snap confinement we
261262
# can securely enable this.
262263
# - -DSNAP_CONFINEMENT=ON

src/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ include_directories(
2929
${CMAKE_SOURCE_DIR}/external/cpu_features/include
3030
)
3131

32+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBINDERFS_PATH=\"\\\"${BINDERFS_PATH}\\\"\"")
33+
3234
protobuf_generate_cpp(
3335
GENERATED_PROTOBUF_RPC_SRCS GENERATED_PROTOBUF_RPC_HDRS
3436
anbox/protobuf/anbox_rpc.proto)
@@ -121,6 +123,11 @@ set(SOURCES
121123
anbox/common/variable_length_array.h
122124
anbox/common/wait_handle.cpp
123125
anbox/common/wait_handle.h
126+
anbox/common/binderfs.h
127+
anbox/common/binder_device.cpp
128+
anbox/common/binder_device.h
129+
anbox/common/binder_device_allocator.cpp
130+
anbox/common/binder_device_allocator.h
124131

125132
anbox/container/client.cpp
126133
anbox/container/client.h

src/anbox/cmds/session_manager.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ anbox::cmds::SessionManager::SessionManager()
129129
return EXIT_FAILURE;
130130
}
131131

132-
if (!fs::exists("/dev/binder") || !fs::exists("/dev/ashmem")) {
132+
if ((!fs::exists("/dev/binder") && !fs::exists(BINDERFS_PATH)) || !fs::exists("/dev/ashmem")) {
133133
ERROR("Failed to start as either binder or ashmem kernel drivers are not loaded");
134134
return EXIT_FAILURE;
135135
}
@@ -269,8 +269,6 @@ anbox::cmds::SessionManager::SessionManager()
269269
};
270270

271271
container_configuration.devices = {
272-
{"/dev/binder", {0666}},
273-
{"/dev/ashmem", {0666}},
274272
{"/dev/fuse", {0666}},
275273
};
276274

src/anbox/common/binder_device.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (C) 2018 Canonical Ltd.
3+
*
4+
* This program is free software: you can redistribute it and/or modify it
5+
* under the terms of the GNU General Public License version 3, as published
6+
* by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful, but
9+
* WITHOUT ANY WARRANTY; without even the implied warranties of
10+
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+
* PURPOSE. See the GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License along
14+
* with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
18+
#include "anbox/common/binder_device.h"
19+
#include "anbox/common/binderfs.h"
20+
#include "anbox/defer_action.h"
21+
#include "anbox/logger.h"
22+
#include "anbox/utils.h"
23+
24+
#include <system_error>
25+
26+
#include <cerrno>
27+
#include <fcntl.h>
28+
#include <linux/loop.h>
29+
#include <sys/ioctl.h>
30+
#include <sys/stat.h>
31+
32+
namespace anbox {
33+
namespace common {
34+
std::unique_ptr<BinderDevice> BinderDevice::create(const std::string& path) {
35+
return std::unique_ptr<BinderDevice>(new BinderDevice(path));
36+
}
37+
38+
BinderDevice::BinderDevice(const std::string& path) :
39+
path_{path} {
40+
if (::chmod(path.c_str(), 0666) < 0)
41+
ERROR("Failed to change permissions of binder node %s: %s", path, std::strerror(errno));
42+
}
43+
44+
BinderDevice::~BinderDevice() {
45+
if (::unlink(path_.c_str()) < 0)
46+
ERROR("Failed to remove binder node %s: %s", path_, std::strerror(errno));
47+
}
48+
} // namespace common
49+
} // namespace anbox

src/anbox/common/binder_device.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2018 Canonical Ltd.
3+
*
4+
* This program is free software: you can redistribute it and/or modify it
5+
* under the terms of the GNU General Public License version 3, as published
6+
* by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful, but
9+
* WITHOUT ANY WARRANTY; without even the implied warranties of
10+
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+
* PURPOSE. See the GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License along
14+
* with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
18+
#ifndef ANBOX_COMMON_BINDER_DEVICE_H_
19+
#define ANBOX_COMMON_BINDER_DEVICE_H_
20+
21+
#include "anbox/common/fd.h"
22+
23+
#include <boost/filesystem/path.hpp>
24+
25+
namespace anbox {
26+
namespace common {
27+
class BinderDevice {
28+
public:
29+
static std::unique_ptr<BinderDevice> create(const std::string& path);
30+
31+
~BinderDevice();
32+
33+
boost::filesystem::path path() const { return path_; }
34+
35+
private:
36+
BinderDevice(const std::string& path);
37+
38+
const std::string path_;
39+
};
40+
} // namespace common
41+
} // namespace anbox
42+
43+
#endif
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (C) 2018 Canonical Ltd.
3+
*
4+
* This program is free software: you can redistribute it and/or modify it
5+
* under the terms of the GNU General Public License version 3, as published
6+
* by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful, but
9+
* WITHOUT ANY WARRANTY; without even the implied warranties of
10+
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+
* PURPOSE. See the GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License along
14+
* with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
18+
#include "anbox/common/binder_device_allocator.h"
19+
#include "anbox/common/binder_device.h"
20+
#include "anbox/common/binderfs.h"
21+
#include "anbox/defer_action.h"
22+
#include "anbox/logger.h"
23+
#include "anbox/utils.h"
24+
25+
#include <boost/filesystem.hpp>
26+
27+
#include <cerrno>
28+
#include <fcntl.h>
29+
#include <linux/loop.h>
30+
#include <sys/ioctl.h>
31+
32+
#include <system_error>
33+
34+
namespace fs = boost::filesystem;
35+
36+
namespace {
37+
const constexpr char* binderfs_base_path{BINDERFS_PATH};
38+
const constexpr char* binderfs_control_path{BINDERFS_PATH "/binder-control"};
39+
const constexpr char* default_binder_device_name{"binder"};
40+
} // namespace
41+
42+
namespace anbox {
43+
namespace common {
44+
bool BinderDeviceAllocator::is_supported() {
45+
return fs::exists(binderfs_control_path);
46+
}
47+
48+
std::unique_ptr<BinderDevice> BinderDeviceAllocator::new_device() {
49+
static uint32_t next_id = 0;
50+
51+
const auto ctl_fd = ::open(binderfs_control_path, O_RDWR);
52+
if (ctl_fd < 0) {
53+
ERROR("Failed to access binder control: %s", std::strerror(errno));
54+
return nullptr;
55+
}
56+
57+
DeferAction close_ctl_fd{[&]() { ::close(ctl_fd); }};
58+
59+
binderfs_device dev;
60+
std::memset(&dev, 0, sizeof(binderfs_device));
61+
62+
const auto device_name = utils::string_format("%s%d", default_binder_device_name, next_id++);
63+
if (device_name.length() > BINDERFS_MAX_NAME) {
64+
ERROR("Invalid binder device name: %s", device_name);
65+
return nullptr;
66+
}
67+
68+
std::memcpy(dev.name, device_name.c_str(), device_name.length());
69+
70+
if (::ioctl(ctl_fd, BINDER_CTL_ADD, &dev) < 0) {
71+
ERROR("Failed to allocate new binder node: %s", std::strerror(errno));
72+
return nullptr;
73+
}
74+
75+
const auto path = utils::string_format("%s/%s", binderfs_base_path, device_name);
76+
if (!fs::exists(path)) {
77+
ERROR("Allocated binder device %s is missing", path);
78+
return nullptr;
79+
}
80+
81+
return BinderDevice::create(path);
82+
}
83+
} // namespace common
84+
} // namespace anbox

0 commit comments

Comments
 (0)