summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--pkgs/build-support/fetchgitiles/default.nix10
-rw-r--r--pkgs/build-support/rust/default.nix3
-rw-r--r--pkgs/build-support/rust/fetchcargo.nix10
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-Adjust-policy-gen-script-cmdline-args.patch109
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-Add-proto-library-and-its-dependencies-for.patch81
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/0003-common-mk-don-t-leak-source-absolute-paths.patch139
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/0004-common-mk-.gn-don-t-hardcode-env-path.patch23
-rw-r--r--pkgs/os-specific/linux/chromium-os/common-mk/default.nix120
-rw-r--r--pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff15
-rw-r--r--pkgs/os-specific/linux/chromium-os/crosvm/default.nix74
-rw-r--r--pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix9
-rw-r--r--pkgs/os-specific/linux/chromium-os/default.nix61
-rw-r--r--pkgs/os-specific/linux/chromium-os/libbrillo/0005-libbrillo-Use-a-unique_ptr-for-EVP_MD_CTX.patch86
-rw-r--r--pkgs/os-specific/linux/chromium-os/libbrillo/0006-libbrillo-Update-for-OpenSSL-1.1.patch218
-rw-r--r--pkgs/os-specific/linux/chromium-os/libbrillo/0007-libbrillo-fix-build-with-relative-platform2_root.patch26
-rw-r--r--pkgs/os-specific/linux/chromium-os/libbrillo/0008-libbrillo-don-t-leak-source-absolute-paths.patch30
-rw-r--r--pkgs/os-specific/linux/chromium-os/libbrillo/0009-libbrillo-fix-build-with-no-__has_feature.patch36
-rw-r--r--pkgs/os-specific/linux/chromium-os/libbrillo/default.nix51
-rw-r--r--pkgs/os-specific/linux/chromium-os/libchrome/0001-Don-t-leak-source-absolute-paths-to-subprocesses.patch40
-rw-r--r--pkgs/os-specific/linux/chromium-os/libchrome/default.nix62
-rw-r--r--pkgs/os-specific/linux/chromium-os/modem-manager/default.nix31
-rw-r--r--pkgs/os-specific/linux/chromium-os/modem-manager/next.nix22
-rw-r--r--pkgs/os-specific/linux/chromium-os/modp_b64/0001-modp_b64-Fix-GN-build-and-add-fuzzers.patch1127
-rw-r--r--pkgs/os-specific/linux/chromium-os/modp_b64/0002-Use-regular-archives.patch36
-rw-r--r--pkgs/os-specific/linux/chromium-os/modp_b64/default.nix30
-rw-r--r--pkgs/os-specific/linux/chromium-os/protofiles/default.nix34
-rw-r--r--pkgs/os-specific/linux/chromium-os/sommelier/0010-sommelier-don-t-leak-source-absolute-paths.patch25
-rw-r--r--pkgs/os-specific/linux/chromium-os/sommelier/0011-sommelier-use-stable-xdg-shell-protocol.patch1749
-rw-r--r--pkgs/os-specific/linux/chromium-os/sommelier/default.nix34
-rwxr-xr-xpkgs/os-specific/linux/chromium-os/update.py117
-rw-r--r--pkgs/os-specific/linux/chromium-os/upstream-info.json55
-rw-r--r--pkgs/os-specific/linux/chromium-os/vm_protos/default.nix31
-rw-r--r--pkgs/os-specific/linux/kernel-headers/default.nix14
-rw-r--r--pkgs/os-specific/linux/kernel/linux-cros.nix34
-rw-r--r--pkgs/os-specific/linux/s6-linux-init/default.nix31
-rw-r--r--pkgs/tools/system/minijail/default.nix24
-rw-r--r--pkgs/top-level/all-packages.nix17
37 files changed, 4592 insertions, 22 deletions
diff --git a/pkgs/build-support/fetchgitiles/default.nix b/pkgs/build-support/fetchgitiles/default.nix
new file mode 100644
index 00000000000..827680992d6
--- /dev/null
+++ b/pkgs/build-support/fetchgitiles/default.nix
@@ -0,0 +1,10 @@
+{ fetchzip, lib }:
+
+{ url, rev, name ? "source", ... } @ args:
+
+fetchzip ({
+  inherit name;
+  url = "${url}/+archive/${rev}.tar.gz";
+  stripRoot = false;
+  meta.homepage = url;
+} // removeAttrs args [ "url" "rev" ]) // { inherit rev; }
diff --git a/pkgs/build-support/rust/default.nix b/pkgs/build-support/rust/default.nix
index 1d8e4448674..f9cf8f1f0c1 100644
--- a/pkgs/build-support/rust/default.nix
+++ b/pkgs/build-support/rust/default.nix
@@ -4,6 +4,7 @@
 , cargoSha256 ? "unset"
 , src ? null
 , srcs ? null
+, unpackPhase ? null
 , cargoPatches ? []
 , patches ? []
 , sourceRoot ? null
@@ -29,7 +30,7 @@ assert buildType == "release" || buildType == "debug";
 let
   cargoDeps = if cargoVendorDir == null
     then fetchcargo {
-        inherit name src srcs sourceRoot cargoUpdateHook;
+        inherit name src srcs sourceRoot unpackPhase cargoUpdateHook;
         copyLockfile = verifyCargoDeps;
         patches = cargoPatches;
         sha256 = cargoSha256;
diff --git a/pkgs/build-support/rust/fetchcargo.nix b/pkgs/build-support/rust/fetchcargo.nix
index a515ce9c6eb..01e410c8bf8 100644
--- a/pkgs/build-support/rust/fetchcargo.nix
+++ b/pkgs/build-support/rust/fetchcargo.nix
@@ -26,11 +26,11 @@ in
 , cargoUpdateHook ? ""
 , # whenever to also include the Cargo.lock in the output
   copyLockfile ? false
-}:
-stdenv.mkDerivation {
+, ...
+} @ args:
+stdenv.mkDerivation ({
   name = "${name}-vendor";
   nativeBuildInputs = [ cacert git cargo-vendor-normalise cargo ];
-  inherit src srcs patches sourceRoot;
 
   phases = "unpackPhase patchPhase installPhase";
 
@@ -76,4 +76,6 @@ stdenv.mkDerivation {
 
   impureEnvVars = stdenv.lib.fetchers.proxyImpureEnvVars;
   preferLocalBuild = true;
-}
+} // (builtins.removeAttrs args [
+  "name" "sha256" "cargoUpdateHook" "copyLockfile"
+]))
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-Adjust-policy-gen-script-cmdline-args.patch b/pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-Adjust-policy-gen-script-cmdline-args.patch
new file mode 100644
index 00000000000..4829d6eba70
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/0001-common-mk-Adjust-policy-gen-script-cmdline-args.patch
@@ -0,0 +1,109 @@
+From fc07988a1837ea947af231d9371a7d7b96618f52 Mon Sep 17 00:00:00 2001
+From: Pavol Marko <pmarko@google.com>
+Date: Wed, 4 Sep 2019 15:21:46 +0200
+Subject: [PATCH 01/11] common-mk: Adjust policy gen script cmdline args
+
+The cmdline args interface of the policy source generation script
+'generate_policy_source.py' has changed on the Chromium side as of
+CL:1687818. Change invocations accordingly.
+While here, remove the targets 'cloud_policy_proto_generator' /
+'user_policy-protos' of common-mk/external_dependencies.gyp as the
+usages have been migrated to gn.
+
+BUG=chromium:981128
+TEST=build_packages
+
+Cq-Depend: chromium:1786282
+Change-Id: I308465451c6cee96319ea5ec104a799f1761d3ab
+Reviewed-on: https://chromium-review.googlesource.com/1785600
+Tested-by: Pavol Marko <pmarko@chromium.org>
+Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
+Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
+Reviewed-by: Mike Frysinger <vapier@chromium.org>
+Reviewed-by: Pavol Marko <pmarko@chromium.org>
+---
+ common-mk/external_dependencies.gyp      | 42 ------------------------
+ common-mk/external_dependencies/BUILD.gn |  7 ++--
+ 2 files changed, 3 insertions(+), 46 deletions(-)
+
+diff --git a/common-mk/external_dependencies.gyp b/common-mk/external_dependencies.gyp
+index 34eaa59ce..751f8566d 100644
+--- a/common-mk/external_dependencies.gyp
++++ b/common-mk/external_dependencies.gyp
+@@ -49,33 +49,6 @@
+       ],
+       'includes': ['xml2cpp.gypi'],
+     },
+-    {
+-      'target_name': 'cloud_policy_proto_generator',
+-      'type': 'none',
+-      'hard_dependency': 1,
+-      'variables': {
+-        'policy_tools_dir': '<(sysroot)/usr/share/policy_tools',
+-        'policy_resources_dir': '<(sysroot)/usr/share/policy_resources',
+-        'proto_out_dir': '<(SHARED_INTERMEDIATE_DIR)/proto',
+-      },
+-      'actions': [{
+-        'action_name': 'run_generate_script',
+-        'inputs': [
+-          '<(policy_tools_dir)/generate_policy_source.py',
+-          '<(policy_resources_dir)/policy_templates.json',
+-          '<(policy_resources_dir)/VERSION',
+-        ],
+-        'outputs': [ '<(proto_out_dir)/cloud_policy.proto' ],
+-        'action': [
+-          'python', '<(policy_tools_dir)/generate_policy_source.py',
+-          '--cloud-policy-protobuf=<(proto_out_dir)/cloud_policy.proto',
+-          '<(policy_resources_dir)/VERSION',
+-          '<(OS)',
+-          '1',         # chromeos-flag
+-          '<(policy_resources_dir)/policy_templates.json',
+-        ],
+-      }],
+-    },
+     {
+       'target_name': 'policy-protos',
+       'type': 'static_library',
+@@ -95,21 +68,6 @@
+       ],
+       'includes': ['protoc.gypi'],
+     },
+-    {
+-      'target_name': 'user_policy-protos',
+-      'type': 'static_library',
+-      'variables': {
+-        'proto_in_dir': '<(SHARED_INTERMEDIATE_DIR)/proto',
+-        'proto_out_dir': 'include/bindings',
+-      },
+-      'dependencies': [
+-        'cloud_policy_proto_generator',
+-      ],
+-      'sources': [
+-        '<(proto_in_dir)/cloud_policy.proto',
+-      ],
+-      'includes': ['protoc.gypi'],
+-    },
+     {
+       'target_name': 'install_attributes-proto',
+       'type': 'static_library',
+diff --git a/common-mk/external_dependencies/BUILD.gn b/common-mk/external_dependencies/BUILD.gn
+index 61774bf8f..4ec1665e3 100644
+--- a/common-mk/external_dependencies/BUILD.gn
++++ b/common-mk/external_dependencies/BUILD.gn
+@@ -59,10 +59,9 @@ action("cloud_policy_proto_generator") {
+   ]
+   args = [
+     "--cloud-policy-protobuf=${proto_out_dir}/cloud_policy.proto",
+-    "${policy_resources_dir}/VERSION",
+-    "${OS}",
+-    "1",  # chromeos-flag
+-    "${policy_resources_dir}/policy_templates.json",
++    "--chrome-version-file=${policy_resources_dir}/VERSION",
++    "--target-platform=chromeos",
++    "--policy-templates-file=${policy_resources_dir}/policy_templates.json",
+   ]
+ }
+ 
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-Add-proto-library-and-its-dependencies-for.patch b/pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-Add-proto-library-and-its-dependencies-for.patch
new file mode 100644
index 00000000000..a8430e1e326
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/0002-common-mk-Add-proto-library-and-its-dependencies-for.patch
@@ -0,0 +1,81 @@
+From e0ed9db1d24ad7df27146f37895563f8ebc4d613 Mon Sep 17 00:00:00 2001
+From: Amr Aboelkher <amraboelkher@google.com>
+Date: Wed, 2 Oct 2019 18:08:08 +0200
+Subject: [PATCH 02/11] common-mk: Add proto library and its dependencies for
+ policy common definitions
+
+BUG=chromium:1009436,chromium:1006077,chromium:552439
+TEST=precq passes
+
+Cq-Depend: chromium:1833618
+Change-Id: I12e2f15afba615cd4395eb5818f6ff370d187c73
+Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/1835953
+Tested-by: Amr Aboelkher <amraboelkher@google.com>
+Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
+Reviewed-by: Mike Frysinger <vapier@chromium.org>
+---
+ common-mk/external_dependencies/BUILD.gn | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/common-mk/external_dependencies/BUILD.gn b/common-mk/external_dependencies/BUILD.gn
+index 4ec1665e3..61f571b38 100644
+--- a/common-mk/external_dependencies/BUILD.gn
++++ b/common-mk/external_dependencies/BUILD.gn
+@@ -65,14 +65,30 @@ action("cloud_policy_proto_generator") {
+   ]
+ }
+ 
++proto_library("policy_common_definitions-protos") {
++  proto_in_dir = "${sysroot}/usr/share/protofiles"
++  proto_out_dir = "include/bindings"
++  sources = [
++    "${proto_in_dir}/policy_common_definitions.proto",
++  ]
++
++  # policy-protos.a is used by a shared_libary object: https://crbug.com/715795
++  # Build it with '-fPIC' instead of '-fPIE'.
++  configs = [ "//common-mk:pic" ]
++}
++
+ proto_library("policy-protos") {
+   proto_in_dir = "${sysroot}/usr/share/protofiles"
+   proto_out_dir = "include/bindings"
++  proto_lib_dirs = [ "${sysroot}/usr/share/protofiles" ]
+   sources = [
+     "${proto_in_dir}/chrome_device_policy.proto",
+     "${proto_in_dir}/chrome_extension_policy.proto",
+     "${proto_in_dir}/device_management_backend.proto",
+   ]
++  public_deps = [
++    ":policy_common_definitions-protos",
++  ]
+ 
+   # policy-protos.a is used by a shared_libary object: https://crbug.com/715795
+   # Build it with '-fPIC' instead of '-fPIE'.
+@@ -88,18 +104,23 @@ goproto_library("policy-goprotos") {
+     "${proto_in_dir}/chrome_device_policy.proto",
+     "${proto_in_dir}/chrome_extension_policy.proto",
+     "${proto_in_dir}/device_management_backend.proto",
++    "${proto_in_dir}/policy_common_definitions.proto",
+   ]
+ }
+ 
+ proto_library("user_policy-protos") {
+   proto_in_dir = "${target_gen_dir}/proto"
+   proto_out_dir = "include/bindings"
++  proto_lib_dirs = [ "${sysroot}/usr/share/protofiles" ]
+   sources = [
+     "${proto_in_dir}/cloud_policy.proto",
+   ]
+   deps = [
+     ":cloud_policy_proto_generator",
+   ]
++  public_deps = [
++    ":policy_common_definitions-protos",
++  ]
+ }
+ 
+ proto_library("install_attributes-proto") {
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/0003-common-mk-don-t-leak-source-absolute-paths.patch b/pkgs/os-specific/linux/chromium-os/common-mk/0003-common-mk-don-t-leak-source-absolute-paths.patch
new file mode 100644
index 00000000000..764b997d303
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/0003-common-mk-don-t-leak-source-absolute-paths.patch
@@ -0,0 +1,139 @@
+From b5ac444592d4bd837934d8a657d9ae8b600d7f95 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 24 Nov 2019 16:56:11 +0000
+Subject: [PATCH 03/11] common-mk: don't leak source-absolute paths
+
+Source-absolute paths like //vm_tools/whatever were being leaked to
+subprocesses, which of course didn't know how to understand them.
+With this patch, source-absolute paths are only used to tell GN the
+outputs, and normal Unix paths are passed to subprocesses.
+---
+ common-mk/external_dependencies/BUILD.gn |  3 ++-
+ common-mk/pkg_config.gni                 |  7 +++----
+ common-mk/proto_library.gni              | 21 +++++++++++----------
+ 3 files changed, 16 insertions(+), 15 deletions(-)
+
+diff --git a/common-mk/external_dependencies/BUILD.gn b/common-mk/external_dependencies/BUILD.gn
+index 61f571b38..4cb7b93cf 100644
+--- a/common-mk/external_dependencies/BUILD.gn
++++ b/common-mk/external_dependencies/BUILD.gn
+@@ -47,6 +47,7 @@ genxml2cpp("dbus-proxies") {
+ action("cloud_policy_proto_generator") {
+   policy_resources_dir = "${sysroot}/usr/share/policy_resources"
+   proto_out_dir = "${target_gen_dir}/proto"
++  cloud_policy_protobuf_dir = rebase_path(proto_out_dir)
+   policy_tools_dir = "${sysroot}/usr/share/policy_tools"
+ 
+   script = "${policy_tools_dir}/generate_policy_source.py"
+@@ -58,7 +59,7 @@ action("cloud_policy_proto_generator") {
+     "${proto_out_dir}/cloud_policy.proto",
+   ]
+   args = [
+-    "--cloud-policy-protobuf=${proto_out_dir}/cloud_policy.proto",
++    "--cloud-policy-protobuf=${cloud_policy_protobuf_dir}/cloud_policy.proto",
+     "--chrome-version-file=${policy_resources_dir}/VERSION",
+     "--target-platform=chromeos",
+     "--policy-templates-file=${policy_resources_dir}/policy_templates.json",
+diff --git a/common-mk/pkg_config.gni b/common-mk/pkg_config.gni
+index af3c3fb4c..151c49e56 100644
+--- a/common-mk/pkg_config.gni
++++ b/common-mk/pkg_config.gni
+@@ -81,12 +81,11 @@ template("generate_pkg_config") {
+     if (!defined(output_name)) {
+       output_name = name
+     }
+-    outputs = [
+-      "${target_out_dir}/${output_name}.pc",
+-    ]
++    lib_path = "${target_out_dir}/${output_name}.pc"
++    outputs = [ lib_path ]
+ 
+     script = "//common-mk/generate-pc.py"
+-    args = [ "--output" ] + outputs + [ "--name=" + name ]
++    args = [ "--output", rebase_path(lib_path), "--name=" + name ]
+     if (defined(description)) {
+       args += [ "--description=" + description ]
+     }
+diff --git a/common-mk/proto_library.gni b/common-mk/proto_library.gni
+index 70e32cafc..f6dce2760 100644
+--- a/common-mk/proto_library.gni
++++ b/common-mk/proto_library.gni
+@@ -56,7 +56,7 @@ template("proto_library") {
+ 
+     cc_dir = "${root_gen_dir}/${proto_out_dir}"
+     proto_in_dir = rebase_path(proto_in_dir)
+-    proto_out_dir = rebase_path(proto_out_dir)
++    proto_out_dir = rebase_path(cc_dir)
+ 
+     proto_lib_dirs = [
+       proto_in_dir,
+@@ -92,24 +92,23 @@ template("proto_library") {
+     args += [ "${proto_in_dir}/{{source_name_part}}.proto" ]
+     outputs = []
+     if (gen_python) {
+-      python_dir = "${root_gen_dir}/${proto_out_dir}/py"
+       args += [
+         "--python_out",
+-        "${python_dir}",
++        "${proto_out_dir}/py",
+       ]
+-      outputs += [ "${python_dir}/{{source_name_part}}_pb.py" ]
++      outputs += [ "${cc_dir}/py/{{source_name_part}}_pb.py" ]
+     }
+     if (gen_grpc) {
+       if (gen_grpc_gmock) {
+-        args += [ "--grpc_out=generate_mock_code=true:${cc_dir}" ]
++        args += [ "--grpc_out=generate_mock_code=true:${proto_out_dir}" ]
+         outputs += [ "${cc_dir}/{{source_name_part}}_mock.grpc.pb.h" ]
+       } else {
+-        args += [ "--grpc_out=${cc_dir}" ]
++        args += [ "--grpc_out=${proto_out_dir}" ]
+       }
+       grpc_cpp_plugin = "/usr/bin/grpc_cpp_plugin"
+       args += [
+         "--plugin=protoc-gen-grpc=${grpc_cpp_plugin}",
+-        "--cpp_out=${gen_cpp_mode}${cc_dir}",
++        "--cpp_out=${gen_cpp_mode}${proto_out_dir}",
+       ]
+       outputs += [
+         "${cc_dir}/{{source_name_part}}.grpc.pb.cc",
+@@ -119,7 +118,7 @@ template("proto_library") {
+       ]
+     }
+     if (!gen_grpc && !gen_python) {
+-      args += [ "--cpp_out=${gen_cpp_mode}${cc_dir}" ]
++      args += [ "--cpp_out=${gen_cpp_mode}${proto_out_dir}" ]
+       outputs += [
+         "${cc_dir}/{{source_name_part}}.pb.cc",
+         "${cc_dir}/{{source_name_part}}.pb.h",
+@@ -206,7 +205,9 @@ template("goproto_library") {
+     # otherwise file descriptor var name will conflict.
+     # cf) https://github.com/golang/protobuf/issues/109
+ 
++    cc_dir = "${root_gen_dir}/${proto_out_dir}"
+     proto_in_dir = rebase_path(invoker.proto_in_dir)
++    proto_out_dir = rebase_path(cc_dir)
+ 
+     # Build protoc command line to run.
+     script = "//common-mk/file_generator_wrapper.py"
+@@ -222,7 +223,7 @@ template("goproto_library") {
+       "--proto_path",
+       "${sysroot}/usr/share/proto",
+       "--go_out",
+-      "${go_out_prefix}${root_gen_dir}/${proto_out_dir}",
++      "${go_out_prefix}${proto_out_dir}",
+     ]
+     foreach(source, sources) {
+       args += [ rebase_path(source) ]
+@@ -232,7 +233,7 @@ template("goproto_library") {
+     outputs = []
+     foreach(source, invoker.sources) {
+       name = get_path_info(source, "name")
+-      outputs += [ "${root_gen_dir}/${proto_out_dir}/${name}.pb.go" ]
++      outputs += [ "${cc_dir}/${name}.pb.go" ]
+     }
+   }
+ }
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/0004-common-mk-.gn-don-t-hardcode-env-path.patch b/pkgs/os-specific/linux/chromium-os/common-mk/0004-common-mk-.gn-don-t-hardcode-env-path.patch
new file mode 100644
index 00000000000..2ab893d04fa
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/0004-common-mk-.gn-don-t-hardcode-env-path.patch
@@ -0,0 +1,23 @@
+From 11dbc10898cef09008e4ab9d34d855a5e8c12e71 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 24 Nov 2019 17:20:46 +0000
+Subject: [PATCH 04/11] common-mk: .gn: don't hardcode env path
+
+This is needlessly non-portable.
+---
+ .gn | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/.gn b/.gn
+index e7dba8c91..e29fcd61e 100644
+--- a/.gn
++++ b/.gn
+@@ -7,4 +7,4 @@ root = "//common-mk/gn_root/:"
+ 
+ # This makes all scripts run by gn respect the shebang setting of the script.
+ # Otherwise, the default is to always use `python`.
+-script_executable = "/usr/bin/env"
++script_executable = "env"
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/common-mk/default.nix b/pkgs/os-specific/linux/chromium-os/common-mk/default.nix
new file mode 100644
index 00000000000..1ebfbfaac70
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/common-mk/default.nix
@@ -0,0 +1,120 @@
+{ stdenv, lib, fetchFromGitiles, upstreamInfo, gn, pkgconfig, python3, ninja
+, libchrome
+}:
+
+{ platformSubdir
+
+# Mandatory, unlike in mkDerivation, because Google doesn't provide
+# install tasks and just does that in their ebuilds.
+, installPhase
+
+# src allows an out-of-tree (i.e., out-of-platform2) package to be
+# built with common-mk.  patches will be applied to `src` -- to patch
+# platform2 itself use platform2Patches.
+, src ? null, platform2Patches ? []
+
+# gnArgs allows structured data (attribute sets) to be serialized and
+# passed to gn, unlike gnFlags provided by gn's setupHook, which is a
+# flat list of strings.
+, gnArgs ? {}, gnFlags ? [], use ? {}
+
+, postUnpack ? "", prePatch ? "", postPatch ? ""
+, nativeBuildInputs ? []
+, meta ? {}
+, ... } @ args:
+
+let
+  platform2 = fetchFromGitiles upstreamInfo.components."chromiumos/platform2";
+
+  attrsToGnList = lib.mapAttrsToList (name: value: "${name}=${toGn value}");
+
+  toGn = value:
+    if lib.isAttrs value then
+      "{${lib.concatStringsSep " " (attrsToGnList value)}}"
+    else
+      builtins.toJSON value;
+in
+
+stdenv.mkDerivation ({
+  pname = lib.last (lib.splitString "/" platformSubdir);
+  inherit (upstreamInfo) version;
+
+  srcs = [ platform2 ] ++ lib.optional (src != null) src;
+  sourceRoot = "platform2";
+
+  postUnpack = lib.optionalString (src != null) ''
+    ln -s ../${src.name} $sourceRoot/${platformSubdir}
+    chmod -R +w ${src.name}
+  '' + postUnpack;
+
+  prePatch = ''
+    pushd ${platformSubdir}
+  '' + prePatch;
+
+  postPatch = ''
+    popd
+    ${lib.concatMapStrings (patch: ''
+      echo applying patch ${patch}
+      patch -p1 < ${patch} 
+    '') ([
+      ./0001-common-mk-Adjust-policy-gen-script-cmdline-args.patch
+      ./0002-common-mk-Add-proto-library-and-its-dependencies-for.patch
+      ./0003-common-mk-don-t-leak-source-absolute-paths.patch
+      ./0004-common-mk-.gn-don-t-hardcode-env-path.patch
+    ] ++ platform2Patches)}
+
+    patchShebangs common-mk
+  '' + (lib.optionalString (!stdenv.cc.isClang) ''
+    substituteInPlace common-mk/BUILD.gn \
+        --replace '"-Wno-c99-designator",' ""
+  '') + postPatch;
+
+  nativeBuildInputs = [ gn pkgconfig python3 ninja ] ++ nativeBuildInputs;
+
+  gnFlags = (attrsToGnList ({
+    ar = "ar";
+    cc = "cc";
+    cxx = "c++";
+    libbase_ver = libchrome.version;
+    libdir = placeholder "out";
+    pkg_config = "pkg-config";
+    platform2_root = ".";
+    platform_subdir = platformSubdir;
+    use = {
+      amd64 = stdenv.targetPlatform.isx86_64;
+      arm = stdenv.targetPlatform.isAarch32 || stdenv.targetPlatform.isAarch64;
+      asan = false;
+      coverage = false;
+      cros_host = false;
+      crypto = false;
+      dbus = false;
+      device_mapper = false;
+      fuzzer = false;
+      mojo = false;
+      profiling = false;
+      tcmalloc = false;
+      test = false;
+      timers = false;
+      udev = false;
+    } // use;
+  } // gnArgs)) ++ gnFlags;
+
+  passthru.updateScript = ../update.py;
+
+  meta = {
+    homepage =
+      if src == null then
+        "${platform2.meta.homepage}/+/HEAD/${platformSubdir}"
+      else
+        src.meta.homepage;
+    platform = lib.platforms.linux;
+  } // lib.optionalAttrs (src == null) {
+    license = lib.licenses.bsd3;
+  } // meta;
+} // (builtins.removeAttrs args [
+  "src"
+  "gnArgs" "gnFlags" "use"
+  "postUnpack" "prePatch" "postPatch"
+  "nativeBuildInputs"
+  "meta"
+]))
diff --git a/pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff b/pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff
new file mode 100644
index 00000000000..f1aa50ee102
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/crosvm/default-seccomp-policy-dir.diff
@@ -0,0 +1,15 @@
+diff --git a/src/crosvm.rs b/src/crosvm.rs
+index b7055df..5989c87 100644
+--- a/src/crosvm.rs
++++ b/src/crosvm.rs
+@@ -141,7 +141,9 @@ impl Default for Config {
+             x_display: None,
+             shared_dirs: Vec::new(),
+             sandbox: !cfg!(feature = "default-no-sandbox"),
+-            seccomp_policy_dir: PathBuf::from(SECCOMP_POLICY_DIR),
++            seccomp_policy_dir: PathBuf::from(
++                option_env!("DEFAULT_SECCOMP_POLICY_DIR").unwrap_or(SECCOMP_POLICY_DIR),
++            ),
+             seccomp_log_failures: false,
+             cras_audio: false,
+             cras_capture: false,
diff --git a/pkgs/os-specific/linux/chromium-os/crosvm/default.nix b/pkgs/os-specific/linux/chromium-os/crosvm/default.nix
new file mode 100644
index 00000000000..648fef71616
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/crosvm/default.nix
@@ -0,0 +1,74 @@
+{ stdenv, rustPlatform, fetchFromGitiles, upstreamInfo
+, pkgconfig, minijail, dtc, libusb1, libcap
+}:
+
+let
+  arch = with stdenv.hostPlatform;
+    if isAarch64 then "arm"
+    else if isx86_64 then "x86_64"
+    else throw "no seccomp policy files available for host platform";
+
+  crosvmSrc = fetchFromGitiles
+    upstreamInfo.components."chromiumos/platform/crosvm";
+
+  adhdSrc = fetchFromGitiles
+    upstreamInfo.components."chromiumos/third_party/adhd";
+in
+
+  rustPlatform.buildRustPackage rec {
+    pname = "crosvm";
+    inherit (upstreamInfo) version;
+
+    unpackPhase = ''
+      runHook preUnpack
+
+      mkdir -p chromiumos/platform chromiumos/third_party
+
+      pushd chromiumos/platform
+      unpackFile ${crosvmSrc}
+      popd
+
+      pushd chromiumos/third_party
+      unpackFile ${adhdSrc}
+      popd
+
+      chmod -R u+w -- "$sourceRoot"
+
+      runHook postUnpack
+    '';
+
+    sourceRoot = "chromiumos/platform/crosvm";
+
+    patches = [
+      ./default-seccomp-policy-dir.diff
+    ];
+
+    cargoSha256 = "1b5i9gwrw55p89f7vwjy801q26hwyn8hd64w6qp66fl9fr7vgvbi";
+
+    nativeBuildInputs = [ pkgconfig ];
+
+    buildInputs = [ dtc libcap libusb1 minijail ];
+
+    postPatch = ''
+      sed -i "s|/usr/share/policy/crosvm/|$out/share/policy/|g" \
+             seccomp/*/*.policy
+    '';
+
+    preBuild = ''
+      export DEFAULT_SECCOMP_POLICY_DIR=$out/share/policy
+    '';
+
+    postInstall = ''
+      mkdir -p $out/share/policy/
+      cp seccomp/${arch}/* $out/share/policy/
+    '';
+
+    passthru.updateScript = ./update.py;
+
+    meta = with stdenv.lib; {
+      description = "A secure virtual machine monitor for KVM";
+      homepage = "https://chromium.googlesource.com/chromiumos/platform/crosvm/";
+      license = licenses.bsd3;
+      platforms = [ "aarch64-linux" "x86_64-linux" ];
+    };
+  }
diff --git a/pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix b/pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix
new file mode 100644
index 00000000000..e95ef4a9aa8
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/dbus-properties/default.nix
@@ -0,0 +1,9 @@
+{ runCommand, chromiumos-overlay }:
+
+runCommand "dbus-properties" {
+  passthru.updateScript = ../update.py;
+} ''
+  mkdir -p $out/share/dbus-1/interfaces
+  cp ${chromiumos-overlay}/sys-apps/dbus/files/org.freedesktop.DBus.Properties.xml \
+      $out/share/dbus-1/interfaces
+''
diff --git a/pkgs/os-specific/linux/chromium-os/default.nix b/pkgs/os-specific/linux/chromium-os/default.nix
new file mode 100644
index 00000000000..6f180d79226
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/default.nix
@@ -0,0 +1,61 @@
+{ newScope, fetchFromGitiles, symlinkJoin
+, linux_4_19, makeLinuxHeaders, modemmanager
+}:
+
+let
+  self = with self; {
+    callPackage = newScope self;
+
+    upstreamInfo = with builtins; fromJSON (readFile ./upstream-info.json);
+
+    chromiumos-overlay = (fetchFromGitiles
+      upstreamInfo.components."chromiumos/overlays/chromiumos-overlay") // {
+        passthru.updateScript = ./update.py;
+      };
+
+    common-mk = callPackage ./common-mk { };
+
+    crosvm = callPackage ./crosvm { };
+
+    dbus-properties = callPackage ./dbus-properties { };
+
+    dbus-interfaces = symlinkJoin {
+      name = "dbus-interfaces";
+      paths = [ dbus-properties self.modemmanager modemmanager-next ];
+      passthru.updateScript = ./update.py;
+    };
+
+    libbrillo = callPackage ./libbrillo { };
+
+    libchrome = callPackage ./libchrome { };
+
+    linux_4_19 = callPackage ../kernel/linux-cros.nix {
+      inherit (linux_4_19) kernelPatches;
+    };
+
+    linux = self.linux_4_19;
+
+    linuxHeaders = makeLinuxHeaders {
+      inherit (linux) version src;
+    };
+
+    modemmanager = callPackage ./modem-manager {
+      inherit modemmanager;
+    };
+
+    modemmanager-next = callPackage ./modem-manager/next.nix {
+      inherit modemmanager;
+    };
+
+    modp_b64 = callPackage ./modp_b64 { };
+
+    protofiles = callPackage ./protofiles { };
+
+    sommelier = callPackage ./sommelier { };
+
+    vm_protos = callPackage ./vm_protos { };
+  };
+
+in self // (with self; {
+  inherit (upstreamInfo) version;
+})
diff --git a/pkgs/os-specific/linux/chromium-os/libbrillo/0005-libbrillo-Use-a-unique_ptr-for-EVP_MD_CTX.patch b/pkgs/os-specific/linux/chromium-os/libbrillo/0005-libbrillo-Use-a-unique_ptr-for-EVP_MD_CTX.patch
new file mode 100644
index 00000000000..eebe6015546
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libbrillo/0005-libbrillo-Use-a-unique_ptr-for-EVP_MD_CTX.patch
@@ -0,0 +1,86 @@
+From ed2920bc6864e044ffa5beb8a2508f4e5f5b4ce4 Mon Sep 17 00:00:00 2001
+From: Daniel Kurtz <djkurtz@chromium.org>
+Date: Thu, 17 Oct 2019 20:45:53 +1100
+Subject: [PATCH 05/11] libbrillo: Use a unique_ptr for EVP_MD_CTX
+
+In OpenSSL 1.1, the EVP_MD_CTX struct will become opaque, and therefore
+it will not be possible to allocate on the stack.
+
+Replace this stack allocation with a heap allocated EVP_MD_CTX using the
+existing OpenSSL 1.0.2 create/destroy APIs, and manage its lifetime using
+a unique_ptr<>.
+
+Note: There are cases (sludge, tael, tatl), where libbrillo is built
+against a libchrome that has been built w/out libbase-crypto (ie,
+USE="-crypto").  For this reason, we don't use the equivalent
+crypto::ScopedEVP_MD_CTX type for this one instance of this in libbrillo.
+
+BUG=chromium:737445
+TEST=cros_workon --board=sarien start libbrillo
+TEST=w/ openssl-1.0.2t: FEATURES=test emerge-sarien libbrillo
+TEST=w/ openssl-1.1.0j: FEATURES=test emerge-sarien libbrillo
+  => Both build and pass all unittests
+
+Change-Id: Ic0a43b9c85fcb967c1b381b1602c03f48ac5dcef
+Reviewed-on: https://chromium-review.googlesource.com/1866378
+Tested-by: Daniel Kurtz <djkurtz@chromium.org>
+Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
+Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
+Reviewed-by: Mike Frysinger <vapier@chromium.org>
+Reviewed-by: Nick Crews <ncrews@chromium.org>
+---
+ libbrillo/policy/device_policy_impl.cc | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+diff --git a/libbrillo/policy/device_policy_impl.cc b/libbrillo/policy/device_policy_impl.cc
+index 6ba297406..e3c12f9d6 100644
+--- a/libbrillo/policy/device_policy_impl.cc
++++ b/libbrillo/policy/device_policy_impl.cc
+@@ -55,36 +55,34 @@ bool ReadPublicKeyFromFile(const base::FilePath& key_file,
+ bool VerifySignature(const std::string& signed_data,
+                      const std::string& signature,
+                      const std::string& public_key) {
+-  EVP_MD_CTX ctx;
+-  EVP_MD_CTX_init(&ctx);
++  std::unique_ptr<EVP_MD_CTX, void (*)(EVP_MD_CTX *)> ctx(EVP_MD_CTX_create(),
++                                                          EVP_MD_CTX_destroy);
++  if (!ctx)
++    return false;
+ 
+   const EVP_MD* digest = EVP_sha1();
+ 
+   char* key = const_cast<char*>(public_key.data());
+   BIO* bio = BIO_new_mem_buf(key, public_key.length());
+-  if (!bio) {
+-    EVP_MD_CTX_cleanup(&ctx);
++  if (!bio)
+     return false;
+-  }
+ 
+   EVP_PKEY* public_key_ssl = d2i_PUBKEY_bio(bio, nullptr);
+   if (!public_key_ssl) {
+     BIO_free_all(bio);
+-    EVP_MD_CTX_cleanup(&ctx);
+     return false;
+   }
+ 
+   const unsigned char* sig =
+       reinterpret_cast<const unsigned char*>(signature.data());
+-  int rv = EVP_VerifyInit_ex(&ctx, digest, nullptr);
++  int rv = EVP_VerifyInit_ex(ctx.get(), digest, nullptr);
+   if (rv == 1) {
+-    EVP_VerifyUpdate(&ctx, signed_data.data(), signed_data.length());
+-    rv = EVP_VerifyFinal(&ctx, sig, signature.length(), public_key_ssl);
++    EVP_VerifyUpdate(ctx.get(), signed_data.data(), signed_data.length());
++    rv = EVP_VerifyFinal(ctx.get(), sig, signature.length(), public_key_ssl);
+   }
+ 
+   EVP_PKEY_free(public_key_ssl);
+   BIO_free_all(bio);
+-  EVP_MD_CTX_cleanup(&ctx);
+ 
+   return rv == 1;
+ }
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/libbrillo/0006-libbrillo-Update-for-OpenSSL-1.1.patch b/pkgs/os-specific/linux/chromium-os/libbrillo/0006-libbrillo-Update-for-OpenSSL-1.1.patch
new file mode 100644
index 00000000000..bc49b8fa4fd
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libbrillo/0006-libbrillo-Update-for-OpenSSL-1.1.patch
@@ -0,0 +1,218 @@
+From 1c81e92e7a983c2f9fff7bd56ce769f2edb59a59 Mon Sep 17 00:00:00 2001
+From: Daniel Kurtz <djkurtz@chromium.org>
+Date: Mon, 3 Jun 2019 16:46:17 -0600
+Subject: [PATCH 06/11] libbrillo: Update for OpenSSL 1.1
+
+OpenSSL 1.1 has made significant non-backwards compatible changes to its
+API as outlined in:
+https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
+
+Note: There are cases (sludge, tael, tatl), where libbrillo is built
+against a libchrome that has been built w/out libbase-crypto (ie,
+USE="-crypto").  For this reason, we don't use its libcrypto-compat.h.
+
+BUG=chromium:737445
+TEST=cros_workon --board=sarien start libbrillo
+TEST=w/ openssl-1.0.2t: FEATURES=test emerge-sarien libbrillo
+TEST=w/ openssl-1.1.0j: FEATURES=test emerge-sarien libbrillo
+ => Both build and pass all unittests
+
+Change-Id: I911c733e63ccbe58b7d9ef6d8e84c9e121056725
+Reviewed-on: https://chromium-review.googlesource.com/1641754
+Tested-by: Daniel Kurtz <djkurtz@chromium.org>
+Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
+Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
+Reviewed-by: Mike Frysinger <vapier@chromium.org>
+Reviewed-by: Nick Crews <ncrews@chromium.org>
+---
+ .../brillo/streams/openssl_stream_bio.cc      | 75 ++++++++++++++++---
+ libbrillo/brillo/streams/tls_stream.cc        |  7 +-
+ libbrillo/policy/device_policy_impl.cc        | 10 ++-
+ 3 files changed, 77 insertions(+), 15 deletions(-)
+
+diff --git a/libbrillo/brillo/streams/openssl_stream_bio.cc b/libbrillo/brillo/streams/openssl_stream_bio.cc
+index a63d9c0cc..478b11233 100644
+--- a/libbrillo/brillo/streams/openssl_stream_bio.cc
++++ b/libbrillo/brillo/streams/openssl_stream_bio.cc
+@@ -13,9 +13,32 @@ namespace brillo {
+ 
+ namespace {
+ 
++// TODO(crbug.com/984789): Remove once support for OpenSSL <1.1 is dropped.
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++static void BIO_set_data(BIO* a, void* ptr) {
++  a->ptr = ptr;
++}
++
++static void* BIO_get_data(BIO* a) {
++  return a->ptr;
++}
++
++static void BIO_set_init(BIO* a, int init) {
++  a->init = init;
++}
++
++static int BIO_get_init(BIO* a) {
++  return a->init;
++}
++
++static void BIO_set_shutdown(BIO* a, int shut) {
++  a->shutdown = shut;
++}
++#endif
++
+ // Internal functions for implementing OpenSSL BIO on brillo::Stream.
+ int stream_write(BIO* bio, const char* buf, int size) {
+-  brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr);
++  brillo::Stream* stream = static_cast<brillo::Stream*>(BIO_get_data(bio));
+   size_t written = 0;
+   BIO_clear_retry_flags(bio);
+   if (!stream->WriteNonBlocking(buf, size, &written, nullptr))
+@@ -30,7 +53,7 @@ int stream_write(BIO* bio, const char* buf, int size) {
+ }
+ 
+ int stream_read(BIO* bio, char* buf, int size) {
+-  brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr);
++  brillo::Stream* stream = static_cast<brillo::Stream*>(BIO_get_data(bio));
+   size_t read = 0;
+   BIO_clear_retry_flags(bio);
+   bool eos = false;
+@@ -49,16 +72,16 @@ int stream_read(BIO* bio, char* buf, int size) {
+ // NOLINTNEXTLINE(runtime/int)
+ long stream_ctrl(BIO* bio, int cmd, long /* num */, void* /* ptr */) {
+   if (cmd == BIO_CTRL_FLUSH) {
+-    brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr);
++    brillo::Stream* stream = static_cast<brillo::Stream*>(BIO_get_data(bio));
+     return stream->FlushBlocking(nullptr) ? 1 : 0;
+   }
+   return 0;
+ }
+ 
+ int stream_new(BIO* bio) {
+-  bio->shutdown = 0;  // By default do not close underlying stream on shutdown.
+-  bio->init = 0;
+-  bio->num = -1;  // not used.
++  // By default do not close underlying stream on shutdown.
++  BIO_set_shutdown(bio, 0);
++  BIO_set_init(bio, 0);
+   return 1;
+ }
+ 
+@@ -66,13 +89,17 @@ int stream_free(BIO* bio) {
+   if (!bio)
+     return 0;
+ 
+-  if (bio->init) {
+-    bio->ptr = nullptr;
+-    bio->init = 0;
++  if (BIO_get_init(bio)) {
++    BIO_set_data(bio, nullptr);
++    BIO_set_init(bio, 0);
+   }
+   return 1;
+ }
+ 
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++// TODO(crbug.com/984789): Remove #ifdef once support for OpenSSL <1.1 is
++// dropped.
++
+ // BIO_METHOD structure describing the BIO built on top of brillo::Stream.
+ BIO_METHOD stream_method = {
+     0x7F | BIO_TYPE_SOURCE_SINK,  // type: 0x7F is an arbitrary unused type ID.
+@@ -87,13 +114,37 @@ BIO_METHOD stream_method = {
+     nullptr,       // callback function, not used
+ };
+ 
++BIO_METHOD* stream_get_method() {
++  return &stream_method;
++}
++
++#else
++
++BIO_METHOD* stream_get_method() {
++  static BIO_METHOD* stream_method;
++
++  if (!stream_method) {
++    stream_method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK,
++                                 "stream");
++    BIO_meth_set_write(stream_method, stream_write);
++    BIO_meth_set_read(stream_method, stream_read);
++    BIO_meth_set_ctrl(stream_method, stream_ctrl);
++    BIO_meth_set_create(stream_method, stream_new);
++    BIO_meth_set_destroy(stream_method, stream_free);
++  }
++
++  return stream_method;
++}
++
++#endif
++
+ }  // anonymous namespace
+ 
+ BIO* BIO_new_stream(brillo::Stream* stream) {
+-  BIO* bio = BIO_new(&stream_method);
++  BIO* bio = BIO_new(stream_get_method());
+   if (bio) {
+-    bio->ptr = stream;
+-    bio->init = 1;
++    BIO_set_data(bio, stream);
++    BIO_set_init(bio, 1);
+   }
+   return bio;
+ }
+diff --git a/libbrillo/brillo/streams/tls_stream.cc b/libbrillo/brillo/streams/tls_stream.cc
+index 603bd1d54..cc63258db 100644
+--- a/libbrillo/brillo/streams/tls_stream.cc
++++ b/libbrillo/brillo/streams/tls_stream.cc
+@@ -68,6 +68,11 @@ const char kCACertificatePath[] =
+ 
+ namespace brillo {
+ 
++// TODO(crbug.com/984789): Remove once support for OpenSSL <1.1 is dropped.
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#define TLS_client_method() TLSv1_2_client_method()
++#endif
++
+ // Helper implementation of TLS stream used to hide most of OpenSSL inner
+ // workings from the users of brillo::TlsStream.
+ class TlsStream::TlsStreamImpl {
+@@ -342,7 +347,7 @@ bool TlsStream::TlsStreamImpl::Init(StreamPtr socket,
+                                     const base::Closure& success_callback,
+                                     const Stream::ErrorCallback& error_callback,
+                                     ErrorPtr* error) {
+-  ctx_.reset(SSL_CTX_new(TLSv1_2_client_method()));
++  ctx_.reset(SSL_CTX_new(TLS_client_method()));
+   if (!ctx_)
+     return ReportError(error, FROM_HERE, "Cannot create SSL_CTX");
+ 
+diff --git a/libbrillo/policy/device_policy_impl.cc b/libbrillo/policy/device_policy_impl.cc
+index e3c12f9d6..0c112a1b9 100644
+--- a/libbrillo/policy/device_policy_impl.cc
++++ b/libbrillo/policy/device_policy_impl.cc
+@@ -30,6 +30,12 @@ namespace em = enterprise_management;
+ 
+ namespace policy {
+ 
++// TODO(crbug.com/984789): Remove once support for OpenSSL <1.1 is dropped.
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#define EVP_MD_CTX_new EVP_MD_CTX_create
++#define EVP_MD_CTX_free EVP_MD_CTX_destroy
++#endif
++
+ // Maximum value of RollbackAllowedMilestones policy.
+ const int kMaxRollbackAllowedMilestones = 4;
+ 
+@@ -55,8 +61,8 @@ bool ReadPublicKeyFromFile(const base::FilePath& key_file,
+ bool VerifySignature(const std::string& signed_data,
+                      const std::string& signature,
+                      const std::string& public_key) {
+-  std::unique_ptr<EVP_MD_CTX, void (*)(EVP_MD_CTX *)> ctx(EVP_MD_CTX_create(),
+-                                                          EVP_MD_CTX_destroy);
++  std::unique_ptr<EVP_MD_CTX, void (*)(EVP_MD_CTX *)> ctx(EVP_MD_CTX_new(),
++                                                          EVP_MD_CTX_free);
+   if (!ctx)
+     return false;
+ 
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/libbrillo/0007-libbrillo-fix-build-with-relative-platform2_root.patch b/pkgs/os-specific/linux/chromium-os/libbrillo/0007-libbrillo-fix-build-with-relative-platform2_root.patch
new file mode 100644
index 00000000000..d3a4976286d
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libbrillo/0007-libbrillo-fix-build-with-relative-platform2_root.patch
@@ -0,0 +1,26 @@
+From 16960cbb59804aebc4b7dd5f746d2452c8a1edd0 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 1 Dec 2019 22:11:39 +0000
+Subject: [PATCH 07/11] libbrillo: fix build with relative platform2_root
+
+---
+ libbrillo/BUILD.gn | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/libbrillo/BUILD.gn b/libbrillo/BUILD.gn
+index e475692ab..c3ca0054b 100644
+--- a/libbrillo/BUILD.gn
++++ b/libbrillo/BUILD.gn
+@@ -355,7 +355,8 @@ shared_library("libpolicy-${libbase_ver}") {
+     "openssl",
+     "protobuf-lite",
+   ]
+-  ldflags = [ "-Wl,--version-script,${platform2_root}/libbrillo/libpolicy.ver" ]
++  libpolicy_ver = rebase_path("//libbrillo/libpolicy.ver")
++  ldflags = [ "-Wl,--version-script,${libpolicy_ver}" ]
+   sources = [
+     "policy/device_policy.cc",
+     "policy/device_policy_impl.cc",
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/libbrillo/0008-libbrillo-don-t-leak-source-absolute-paths.patch b/pkgs/os-specific/linux/chromium-os/libbrillo/0008-libbrillo-don-t-leak-source-absolute-paths.patch
new file mode 100644
index 00000000000..523a2359bdd
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libbrillo/0008-libbrillo-don-t-leak-source-absolute-paths.patch
@@ -0,0 +1,30 @@
+From 308678664652685d48dccc4ea6d55195a307e36d Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 1 Dec 2019 14:55:21 +0000
+Subject: [PATCH 08/11] libbrillo: don't leak source-absolute paths
+
+---
+ libbrillo/BUILD.gn | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/libbrillo/BUILD.gn b/libbrillo/BUILD.gn
+index c3ca0054b..4ae5aced0 100644
+--- a/libbrillo/BUILD.gn
++++ b/libbrillo/BUILD.gn
+@@ -260,10 +260,9 @@ action("libbrillo-${libbase_ver}") {
+     deps += [ ":lib" + sublib.library_name ]
+   }
+   script = "//common-mk/write_args.py"
+-  outputs = [
+-    "${root_out_dir}/lib/libbrillo-${libbase_ver}.so",
+-  ]
+-  args = [ "--output" ] + outputs + [ "--" ] + [
++  lib_path = "${root_out_dir}/lib/libbrillo-${libbase_ver}.so"
++  outputs = [ lib_path ]
++  args = [ "--output", rebase_path(lib_path), "--",
+            "GROUP",
+            "(",
+            "AS_NEEDED",
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/libbrillo/0009-libbrillo-fix-build-with-no-__has_feature.patch b/pkgs/os-specific/linux/chromium-os/libbrillo/0009-libbrillo-fix-build-with-no-__has_feature.patch
new file mode 100644
index 00000000000..f56439145b4
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libbrillo/0009-libbrillo-fix-build-with-no-__has_feature.patch
@@ -0,0 +1,36 @@
+From dce65ab2cb0bac44cf5a133aface2acf9f0b2367 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 1 Dec 2019 14:57:01 +0000
+Subject: [PATCH 09/11] libbrillo: fix build with no __has_feature
+
+---
+ libbrillo/brillo/asan.h | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/libbrillo/brillo/asan.h b/libbrillo/brillo/asan.h
+index d29932a82..0d707467f 100644
+--- a/libbrillo/brillo/asan.h
++++ b/libbrillo/brillo/asan.h
+@@ -7,13 +7,17 @@
+ #ifndef LIBBRILLO_BRILLO_ASAN_H_
+ #define LIBBRILLO_BRILLO_ASAN_H_
+ 
+-#if defined(__has_feature) && __has_feature(address_sanitizer)
++#if defined(__has_feature)
++#if __has_feature(address_sanitizer)
+ // ASan is enabled.
+ #define BRILLO_ASAN_BUILD 1
+ // Provide BRILLO_DISABLE_ASAN hook to disable ASan.
+ // Put this in front on functions or global variables where required.
+ #define BRILLO_DISABLE_ASAN __attribute__((no_sanitize("address")))
+-#else
++#endif
++#endif
++
++#ifndef BRILLO_DISABLE_ASAN
+ #define BRILLO_DISABLE_ASAN
+ #endif
+ 
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/libbrillo/default.nix b/pkgs/os-specific/linux/chromium-os/libbrillo/default.nix
new file mode 100644
index 00000000000..c5bb961d0cd
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libbrillo/default.nix
@@ -0,0 +1,51 @@
+{ common-mk, lib
+, dbus_cplusplus, go-protobuf, protofiles, dbus-interfaces
+, libchrome, curl, minijail, protobuf, glib, gtest, modp_b64
+}:
+
+common-mk {
+  platformSubdir = "libbrillo";
+
+  platform2Patches = [
+    ./0005-libbrillo-Use-a-unique_ptr-for-EVP_MD_CTX.patch
+    ./0006-libbrillo-Update-for-OpenSSL-1.1.patch
+    ./0007-libbrillo-fix-build-with-relative-platform2_root.patch
+    ./0008-libbrillo-don-t-leak-source-absolute-paths.patch
+    ./0009-libbrillo-fix-build-with-no-__has_feature.patch
+  ];
+
+  nativeBuildInputs = [ dbus_cplusplus go-protobuf ];
+  buildInputs = [ libchrome curl minijail protobuf glib gtest modp_b64 ];
+
+  NIX_CFLAGS_COMPILE = [ "-Wno-error=sign-compare" ];
+
+  postPatch = ''
+    substituteInPlace common-mk/external_dependencies/BUILD.gn \
+        --replace '"''${sysroot}/usr/share/policy_tools"' '"${protofiles}/share/policy_tools"' \
+        --replace '"''${sysroot}/usr/share/policy_resources"' '"${protofiles}/share/policy_resources"' \
+        --replace '"''${sysroot}/usr/share/dbus-1/interfaces/"' '"${dbus-interfaces}/share/dbus-1/interfaces/"' \
+        --replace '"''${sysroot}/usr/include/proto"' '"${protofiles}/include/proto"' \
+        --replace '"''${sysroot}/usr/share/protofiles"' '"${protofiles}/share/protofiles"'
+  '';
+
+  installPhase = ''
+    mkdir -p $out/lib/pkgconfig $out/include/install_attributes
+
+    install lib/*.so $out/lib
+    install libbrillo*.a $out/lib
+    install -m 0644 obj/libbrillo/*.pc $out/lib/pkgconfig
+
+    pushd ../../libbrillo
+    find brillo policy -name '*.h' -print0 \
+        | xargs -t -0 tar -c \
+        | tar -C $out/include -x
+    install -m 0644 install_attributes/libinstallattributes.h \
+        $out/include/install_attributes
+    popd
+  '';
+
+  meta = with lib; {
+    description = "Chromium OS utility library";
+    maintainers = with maintainers; [ qyliss ];
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/libchrome/0001-Don-t-leak-source-absolute-paths-to-subprocesses.patch b/pkgs/os-specific/linux/chromium-os/libchrome/0001-Don-t-leak-source-absolute-paths-to-subprocesses.patch
new file mode 100644
index 00000000000..da58c4b15a7
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libchrome/0001-Don-t-leak-source-absolute-paths-to-subprocesses.patch
@@ -0,0 +1,40 @@
+From a4499cdec93f1b1fd8c2a9db02244d667d9c7e11 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Wed, 27 Nov 2019 17:10:18 +0000
+Subject: [PATCH] Don't leak source-absolute paths to subprocesses
+
+---
+ BUILD.gn | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/BUILD.gn b/BUILD.gn
+index 4477a86..5869e1f 100644
+--- a/BUILD.gn
++++ b/BUILD.gn
+@@ -466,8 +466,9 @@ action("base") {
+   }
+ 
+   script = "//common-mk/write_args.py"
+-  outputs = [ "${root_out_dir}/lib/lib${target_name}-${libbase_ver}.so" ]
+-  args = [ "--output" ] + outputs + [ "--" ] + [
++  lib_path = "${root_out_dir}/lib/lib${target_name}-${libbase_ver}.so"
++  outputs = [ lib_path ]
++  args = [ "--output", rebase_path(lib_path), "--" ] + [
+     "GROUP", "(", "AS_NEEDED", "(",
+   ]
+   foreach(attr, libbase_sublibs) {
+@@ -524,8 +525,9 @@ action("base-test") {
+   }
+ 
+   script = "//common-mk/write_args.py"
+-  outputs = [ "${root_out_dir}/lib${target_name}-${libbase_ver}.a" ]
+-  args = [ "--output" ] + outputs + [ "--" ] + [
++  lib_path = "${root_out_dir}/lib/lib${target_name}-${libbase_ver}.so"
++  outputs = [ lib_path ]
++  args = [ "--output", rebase_path(lib_path), "--" ] + [
+     "GROUP", "(", "AS_NEEDED", "(",
+   ]
+   foreach(attr, libbase_sublibs) {
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/libchrome/default.nix b/pkgs/os-specific/linux/chromium-os/libchrome/default.nix
new file mode 100644
index 00000000000..3aae238e243
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/libchrome/default.nix
@@ -0,0 +1,62 @@
+{ common-mk, stdenv, lib, fetchFromGitiles, upstreamInfo
+, glib, libevent, gmock, modp_b64, chromiumos-overlay
+}:
+
+let
+  versionData = upstreamInfo.components."aosp/platform/external/libchrome";
+in
+
+common-mk rec {
+  platformSubdir = "libchrome";
+  inherit (versionData) version;
+
+  src = fetchFromGitiles { inherit (versionData) name url rev sha256; };
+
+  NIX_CFLAGS_COMPILE = [
+    "-Wno-error=attributes"
+    "-Wno-error=dangling-else"
+    "-Wno-error=implicit-fallthrough"
+    "-Wno-error=unused-function"
+  ];
+
+  buildInputs = [ glib libevent gmock modp_b64 ];
+
+  patches = [
+    ./0001-Don-t-leak-source-absolute-paths-to-subprocesses.patch
+    "${chromiumos-overlay}/chromeos-base/libchrome/files/libchrome-462023-Introduce-ValueReferenceAdapter-for-gracef.patch"
+    "${chromiumos-overlay}/chromeos-base/libchrome/files/libchrome-462023-libchrome-add-alias-from-base-Location-base-GetProgr.patch"
+  ];
+
+  postPatch = ''
+    substituteInPlace libchrome/BUILD.gn \
+        --replace '/usr/include/base-''${libbase_ver}' \
+                  "$out/include/base-\''${libbase_ver}"
+  '' + (if stdenv.cc.isClang then ''
+    substituteInPlace libchrome/BUILD.gn \
+        --replace '"-Xclang-only=-Wno-char-subscripts",' ""
+  '' else ''
+    substituteInPlace libchrome/BUILD.gn \
+        --replace "-Xclang-only=" "" \
+        --replace '"-Wno-deprecated-register",' ""
+  '');
+
+  installPhase = ''
+    mkdir -p $out/lib/pkgconfig
+    install lib/libbase*-$version.so $out/lib
+    install obj/libchrome/libchrome*-$version.pc $out/lib/pkgconfig
+
+    pushd ../../libchrome
+    mkdir -p $out/include/base-$version
+    find . -name '*.h' -print0 \
+        | xargs -0 tar -c \
+        | tar -C $out/include/base-$version -x
+    popd
+  '';
+
+  meta = with lib; {
+    description = "Chromium project utility library";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ qyliss ];
+    platform = platforms.all;
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/modem-manager/default.nix b/pkgs/os-specific/linux/chromium-os/modem-manager/default.nix
new file mode 100644
index 00000000000..c6a5a44b67e
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modem-manager/default.nix
@@ -0,0 +1,31 @@
+{ modemmanager, lib, fetchFromGitiles
+, autoreconfHook, libtool, intltool, libxslt, dbus_glib, chromiumos-overlay
+}:
+
+modemmanager.overrideAttrs (
+  { pname, nativeBuildInputs ? [], buildInputs ? [], postInstall ? "", meta ? {}
+  , ... }:
+  {
+    pname = "${pname}-chromiumos-unstable";
+    version = "2012-04-10";
+
+    src = fetchFromGitiles {
+      url = "https://chromium.googlesource.com/chromiumos/third_party/modemmanager";
+      rev = "657324d1abfd446b0319e4c51bd30cf4967eccf4";
+      sha256 = "12wlak8zx914zix4vv5a8sl0nyi58v7593h4gjchgv3i8ysgj9ah";
+    };
+
+    nativeBuildInputs = nativeBuildInputs ++ [ autoreconfHook libtool intltool libxslt ];
+    buildInputs = buildInputs ++ [ dbus_glib ];
+
+    preAutoreconf = ''
+      intltoolize
+    '';
+
+    NIX_CFLAGS_COMPILE = [ "-Wno-error" ];
+
+    meta = with lib; meta // {
+      maintainers = with maintainers; [ qyliss ];
+    };
+  }
+)
diff --git a/pkgs/os-specific/linux/chromium-os/modem-manager/next.nix b/pkgs/os-specific/linux/chromium-os/modem-manager/next.nix
new file mode 100644
index 00000000000..8ad0e63bf9c
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modem-manager/next.nix
@@ -0,0 +1,22 @@
+{ modemmanager, lib, fetchFromGitiles, upstreamInfo, autoreconfHook, libxslt }:
+
+modemmanager.overrideAttrs (
+  { pname, nativeBuildInputs ? [], passthru ? {}, meta ? {}, ... }:
+  {
+    pname = "${pname}-chromiumos-next-unstable";
+    version = "2019-10-17";
+
+    src = fetchFromGitiles
+      upstreamInfo.components."chromiumos/third_party/modemmanager-next";
+
+    nativeBuildInputs = nativeBuildInputs ++ [ autoreconfHook libxslt ];
+
+    passthru = passthru // {
+      updateScript = ../update.py;
+    };
+
+    meta = with lib; meta // {
+      maintainers = with maintainers; [ qyliss ];
+    };
+  }
+)
diff --git a/pkgs/os-specific/linux/chromium-os/modp_b64/0001-modp_b64-Fix-GN-build-and-add-fuzzers.patch b/pkgs/os-specific/linux/chromium-os/modp_b64/0001-modp_b64-Fix-GN-build-and-add-fuzzers.patch
new file mode 100644
index 00000000000..b5321c9a48c
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modp_b64/0001-modp_b64-Fix-GN-build-and-add-fuzzers.patch
@@ -0,0 +1,1127 @@
+From 832ee65ffff7353e88bf622e2d14e22e991ce698 Mon Sep 17 00:00:00 2001
+From: Manoj Gupta <manojgupta@google.com>
+Date: Wed, 9 Oct 2019 12:40:18 -0700
+Subject: [PATCH 1/2] modp_b64: Fix GN build and add fuzzers.
+
+modp_b64 is currently build with Makefile.
+Fix the BUILD.gn so that it can be used and remove
+Makefile usage.
+Also add two fuzzers for encode and decode routines.
+
+BUG=chromium:1012803
+TEST=GN build work with modified ebuild.
+
+Cq-Depend: chromium:1850664
+Change-Id: I1756237d91630ea7e18e7c3ed055d2b3b532de0d
+---
+ BUILD.gn                          |  53 +-
+ Makefile                          |  20 -
+ OWNERS.fuzzer                     |   1 +
+ common.mk                         | 941 ------------------------------
+ fuzzers/modp_b64_decode_fuzzer.cc |  17 +
+ fuzzers/modp_b64_encode_fuzzer.cc |  17 +
+ 6 files changed, 84 insertions(+), 965 deletions(-)
+ delete mode 100644 Makefile
+ create mode 100644 OWNERS.fuzzer
+ delete mode 100644 common.mk
+ create mode 100644 fuzzers/modp_b64_decode_fuzzer.cc
+ create mode 100644 fuzzers/modp_b64_encode_fuzzer.cc
+
+diff --git a/BUILD.gn b/BUILD.gn
+index cd322ac..b2fe97d 100644
+--- a/BUILD.gn
++++ b/BUILD.gn
+@@ -1,15 +1,60 @@
+-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
++# Copyright 2013 The Chromium Authors. All rights reserved.
+ # Use of this source code is governed by a BSD-style license that can be
+ # found in the LICENSE file.
+ 
+-source_set("modp_b64") {
++group("all") {
++  deps = [
++    ":modp_b64",
++  ]
++
++  if (use.fuzzer) {
++    deps += [
++      ":modp_b64_decode_fuzzer",
++      ":modp_b64_encode_fuzzer",
++    ]
++  }
++}
++
++static_library("modp_b64") {
+   sources = [
+     "modp_b64.cc",
+     "modp_b64.h",
+     "modp_b64_data.h",
+   ]
+-
+   include_dirs = [
+-    "./modp_b64",
++    "modp_b64",
+   ]
+ }
++
++# Fuzzers.
++if (use.fuzzer) {
++  executable("modp_b64_decode_fuzzer") {
++    configs += [
++      "//common-mk/common_fuzzer",
++    ]
++    deps = [
++      ":modp_b64",
++    ]
++    sources = [
++      "fuzzers/modp_b64_decode_fuzzer.cc",
++    ]
++    include_dirs = [
++      "modp_b64",
++    ]
++  }
++
++  executable("modp_b64_encode_fuzzer") {
++    configs += [
++      "//common-mk/common_fuzzer",
++    ]
++    deps = [
++      ":modp_b64",
++    ]
++    sources = [
++      "fuzzers/modp_b64_encode_fuzzer.cc",
++    ]
++    include_dirs = [
++      "modp_b64",
++    ]
++  }
++}
+diff --git a/Makefile b/Makefile
+deleted file mode 100644
+index c33ff75..0000000
+--- a/Makefile
++++ /dev/null
+@@ -1,20 +0,0 @@
+-# Copyright (C) 2015 The Android Open Source Project
+-#
+-# Licensed under the Apache License, Version 2.0 (the "License");
+-# you may not use this file except in compliance with the License.
+-# You may obtain a copy of the License at
+-#
+-#      http://www.apache.org/licenses/LICENSE-2.0
+-#
+-# Unless required by applicable law or agreed to in writing, software
+-# distributed under the License is distributed on an "AS IS" BASIS,
+-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-# See the License for the specific language governing permissions and
+-# limitations under the License.
+-
+-include common.mk
+-
+-CXXFLAGS += -I$(SRC)/modp_b64/
+-CXX_STATIC_LIBRARY(libmodpb64.pie.a): $(CXX_OBJECTS)
+-
+-all: CXX_STATIC_LIBRARY(libmodpb64.pie.a)
+diff --git a/OWNERS.fuzzer b/OWNERS.fuzzer
+new file mode 100644
+index 0000000..62800d6
+--- /dev/null
++++ b/OWNERS.fuzzer
+@@ -0,0 +1 @@
++manojgupta@chromium.org
+diff --git a/common.mk b/common.mk
+deleted file mode 100644
+index 51ead56..0000000
+--- a/common.mk
++++ /dev/null
+@@ -1,941 +0,0 @@
+-# copyright (c) 2012 the chromium os authors. all rights reserved.
+-# use of this source code is governed by a bsd-style license that can be
+-# found in the license file.
+-#
+-# If this file is part of another source distribution, it's license may be
+-# stored in LICENSE.makefile or LICENSE.common.mk.
+-#
+-# NOTE NOTE NOTE
+-#  The authoritative common.mk is located in:
+-#    https://chromium.googlesource.com/chromiumos/platform2/+/master/common-mk
+-#  Please make all changes there, then copy into place in other repos.
+-# NOTE NOTE NOTE
+-#
+-# This file provides a common architecture for building C/C++ source trees.
+-# It uses recursive makefile inclusion to create a single make process which
+-# can be built in the source tree or with the build artifacts placed elsewhere.
+-#
+-# It is fully parallelizable for all targets, including static archives.
+-#
+-# To use:
+-# 1. Place common.mk in your top source level
+-# 2. In your top-level Makefile, place "include common.mk" at the top
+-# 3. In all subdirectories, create a 'module.mk' file that starts with:
+-#      include common.mk
+-#    And then contains the remainder of your targets.
+-# 4. All build targets should look like:
+-#    relative/path/target: relative/path/obj.o
+-#
+-# See existing makefiles for rule examples.
+-#
+-# Exported macros:
+-#   - cc_binary, cxx_binary provide standard compilation steps for binaries
+-#   - cxx_library, cc_library provide standard compilation steps for
+-#     shared objects.
+-#   All of the above optionally take an argument for extra flags.
+-#   - update_archive creates/updates a given .a target
+-#
+-# Instead of using the build macros, most users can just use wrapped targets:
+-#   - CXX_BINARY, CC_BINARY, CC_STATIC_BINARY, CXX_STATIC_BINARY
+-#   - CXX_LIBRARY, CC_LIBRARY, CC_STATIC_LIBRARY, CXX_STATIC_LIBRARY
+-#   - E.g., CXX_BINARY(mahbinary): foo.o
+-#   - object.depends targets may be used when a prerequisite is required for an
+-#     object file. Because object files result in multiple build artifacts to
+-#     handle PIC and PIE weirdness. E.g.
+-#       foo.o.depends: generated/dbus.h
+-#   - TEST(binary) or TEST(CXX_BINARY(binary)) may be used as a prerequisite
+-#     for the tests target to trigger an automated test run.
+-#   - CLEAN(file_or_dir) dependency can be added to 'clean'.
+-#
+-# If source code is being generated, rules will need to be registered for
+-# compiling the objects.  This can be done by adding one of the following
+-# to the Makefile:
+-#   - For C source files
+-#   $(eval $(call add_object_rules,sub/dir/gen_a.o sub/dir/b.o,CC,c,CFLAGS))
+-#   - For C++ source files
+-#   $(eval $(call add_object_rules,sub/dir/gen_a.o sub/dir/b.o,CXX,cc,CXXFLAGS))
+-#
+-# Exported targets meant to have prerequisites added to:
+-#  - all - Your desired targets should be given
+-#  - tests - Any TEST(test_binary) targets should be given
+-#  - FORCE - force the given target to run regardless of changes
+-#            In most cases, using .PHONY is preferred.
+-#
+-# Possible command line variables:
+-#   - COLOR=[0|1] to set ANSI color output (default: 1)
+-#   - VERBOSE=[0|1] to hide/show commands (default: 0)
+-#   - MODE=[opt|dbg|profiling] (default: opt)
+-#          opt - Enable optimizations for release builds
+-#          dbg - Turn down optimization for debugging
+-#          profiling - Turn off optimization and turn on profiling/coverage
+-#                      support.
+-#   - ARCH=[x86|arm|supported qemu name] (default: from portage or uname -m)
+-#   - SPLITDEBUG=[0|1] splits debug info in target.debug (default: 0)
+-#        If NOSTRIP=1, SPLITDEBUG will never strip the final emitted objects.
+-#   - NOSTRIP=[0|1] determines if binaries are stripped. (default: 1)
+-#        NOSTRIP=0 and MODE=opt will also drop -g from the CFLAGS.
+-#   - VALGRIND=[0|1] runs tests under valgrind (default: 0)
+-#   - OUT=/path/to/builddir puts all output in given path (default: $PWD)
+-#   - VALGRIND_ARGS="" supplies extra memcheck arguments
+-#
+-# Per-target(-ish) variable:
+-#   - NEEDS_ROOT=[0|1] allows a TEST() target to run with root.
+-#     Default is 0 unless it is running under QEmu.
+-#   - NEEDS_MOUNTS=[0|1] allows a TEST() target running on QEmu to get
+-#     setup mounts in the $(SYSROOT)
+-#
+-# Caveats:
+-# - Directories or files with spaces in them DO NOT get along with GNU Make.
+-#   If you need them, all uses of dir/notdir/etc will need to have magic
+-#   wrappers.  Proceed at risk to your own sanity.
+-# - External CXXFLAGS and CFLAGS should be passed via the environment since
+-#   this file does not use 'override' to control them.
+-# - Our version of GNU Make doesn't seem to support the 'private' variable
+-#   annotation, so you can't tag a variable private on a wrapping target.
+-
+-# Behavior configuration variables
+-SPLITDEBUG ?= 0
+-NOSTRIP ?= 1
+-VALGRIND ?= 0
+-COLOR ?= 1
+-VERBOSE ?= 0
+-MODE ?= opt
+-CXXEXCEPTIONS ?= 0
+-ARCH ?= $(shell uname -m)
+-
+-# Put objects in a separate tree based on makefile locations
+-# This means you can build a tree without touching it:
+-#   make -C $SRCDIR  # will create ./build-$(MODE)
+-# Or
+-#   make -C $SRCDIR OUT=$PWD
+-# This variable is extended on subdir calls and doesn't need to be re-called.
+-OUT ?= $(PWD)/
+-
+-# Make OUT now so we can use realpath.
+-$(shell mkdir -p "$(OUT)")
+-
+-# TODO(wad) Relative paths are resolved against SRC and not the calling dir.
+-# Ensure a command-line supplied OUT has a slash
+-override OUT := $(realpath $(OUT))/
+-
+-# SRC is not meant to be set by the end user, but during make call relocation.
+-# $(PWD) != $(CURDIR) all the time.
+-export SRC ?= $(CURDIR)
+-
+-# If BASE_VER is not set, read the libchrome revision number from
+-# common-mk/BASE_VER file.
+-ifeq ($(strip $(BASE_VER)),)
+-BASE_VER := $(shell cat $(SRC)/../common-mk/BASE_VER)
+-endif
+-$(info Using BASE_VER=$(BASE_VER))
+-
+-# Re-start in the $(OUT) directory if we're not there.
+-# We may be invoked using -C or bare and we need to ensure behavior
+-# is consistent so we check both PWD vs OUT and PWD vs CURDIR.
+-override RELOCATE_BUILD := 0
+-ifneq (${PWD}/,${OUT})
+-override RELOCATE_BUILD := 1
+-endif
+-# Make sure we're running with no builtin targets. They cause
+-# leakage and mayhem!
+-ifneq (${PWD},${CURDIR})
+-override RELOCATE_BUILD := 1
+-# If we're run from the build dir, don't let it get cleaned up later.
+-ifeq (${PWD}/,${OUT})
+-$(shell touch "$(PWD)/.dont_delete_on_clean")
+-endif
+-endif  # ifneq (${PWD},${CURDIR}
+-
+-# "Relocate" if we need to restart without implicit rules.
+-ifeq ($(subst r,,$(MAKEFLAGS)),$(MAKEFLAGS))
+-override RELOCATE_BUILD := 1
+-endif
+-
+-ifeq (${RELOCATE_BUILD},1)
+-# By default, silence build output. Reused below as well.
+-QUIET = @
+-ifeq ($(VERBOSE),1)
+-  QUIET=
+-endif
+-
+-# This target will override all targets, including prerequisites. To avoid
+-# calling $(MAKE) once per prereq on the given CMDGOAL, we guard it with a local
+-# variable.
+-RUN_ONCE := 0
+-MAKECMDGOALS ?= all
+-# Keep the rules split as newer make does not allow them to be declared
+-# on the same line.  But the way :: rules work, the _all here will also
+-# invoke the %:: rule while retaining "_all" as the default.
+-_all::
+-%::
+-	$(if $(filter 0,$(RUN_ONCE)), \
+-	  cd "$(OUT)" && \
+-	  $(MAKE) -r -I "$(SRC)" -f "$(CURDIR)/Makefile" \
+-	    SRC="$(CURDIR)" OUT="$(OUT)" $(foreach g,$(MAKECMDGOALS),"$(g)"),)
+-	$(eval RUN_ONCE := 1)
+-pass-to-subcall := 1
+-endif
+-
+-ifeq ($(pass-to-subcall),)
+-
+-# Only call MODULE if we're in a submodule
+-MODULES_LIST := $(filter-out Makefile %.d,$(MAKEFILE_LIST))
+-ifeq ($(words $(filter-out Makefile common.mk %.d $(SRC)/Makefile \
+-                           $(SRC)/common.mk,$(MAKEFILE_LIST))),0)
+-
+-# All the top-level defines outside of module.mk.
+-
+-#
+-# Helper macros
+-#
+-
+-# Create the directory if it doesn't yet exist.
+-define auto_mkdir
+-  $(if $(wildcard $(dir $1)),$2,$(QUIET)mkdir -p "$(dir $1)")
+-endef
+-
+-# Creates the actual archive with an index.
+-# The target $@ must end with .pic.a or .pie.a.
+-define update_archive
+-  $(call auto_mkdir,$(TARGET_OR_MEMBER))
+-  $(QUIET)# Create the archive in one step to avoid parallel use accessing it
+-  $(QUIET)# before all the symbols are present.
+-  @$(ECHO) "AR		$(subst \
+-$(SRC)/,,$(^:.o=$(suffix $(basename $(TARGET_OR_MEMBER))).o)) \
+--> $(subst $(SRC)/,,$(TARGET_OR_MEMBER))"
+-  $(QUIET)$(AR) rcs $(TARGET_OR_MEMBER) \
+-          $(subst $(SRC)/,,$(^:.o=$(suffix $(basename $(TARGET_OR_MEMBER))).o))
+-endef
+-
+-# Default compile from objects using pre-requisites but filters out
+-# subdirs and .d files.
+-define cc_binary
+-  $(call COMPILE_BINARY_implementation,CC,$(CFLAGS) $(1),$(EXTRA_FLAGS))
+-endef
+-
+-define cxx_binary
+-  $(call COMPILE_BINARY_implementation,CXX,$(CXXFLAGS) $(1),$(EXTRA_FLAGS))
+-endef
+-
+-# Default compile from objects using pre-requisites but filters out
+-# subdirs and .d files.
+-define cc_library
+-  $(call COMPILE_LIBRARY_implementation,CC,$(CFLAGS) $(1),$(EXTRA_FLAGS))
+-endef
+-define cxx_library
+-  $(call COMPILE_LIBRARY_implementation,CXX,$(CXXFLAGS) $(1),$(EXTRA_FLAGS))
+-endef
+-
+-# Deletes files silently if they exist. Meant for use in any local
+-# clean targets.
+-define silent_rm
+-  $(if $(wildcard $(1)),
+-  $(QUIET)($(ECHO) -n '$(COLOR_RED)CLEANFILE$(COLOR_RESET)		' && \
+-    $(ECHO) '$(subst $(OUT)/,,$(wildcard $(1)))' && \
+-    $(RM) $(1) 2>/dev/null) || true,)
+-endef
+-define silent_rmdir
+-  $(if $(wildcard $(1)),
+-    $(if $(wildcard $(1)/*),
+-  $(QUIET)# $(1) not empty [$(wildcard $(1)/*)]. Not deleting.,
+-  $(QUIET)($(ECHO) -n '$(COLOR_RED)CLEANDIR$(COLOR_RESET)		' && \
+-    $(ECHO) '$(subst $(OUT)/,,$(wildcard $(1)))' && \
+-    $(RMDIR) $(1) 2>/dev/null) || true),)
+-endef
+-
+-#
+-# Default variable values
+-#
+-
+-# Only override toolchain vars if they are from make.
+-CROSS_COMPILE ?=
+-define override_var
+-ifneq ($(filter undefined default,$(origin $1)),)
+-$1 = $(CROSS_COMPILE)$2
+-endif
+-endef
+-$(eval $(call override_var,AR,ar))
+-$(eval $(call override_var,CC,gcc))
+-$(eval $(call override_var,CXX,g++))
+-$(eval $(call override_var,OBJCOPY,objcopy))
+-$(eval $(call override_var,PKG_CONFIG,pkg-config))
+-$(eval $(call override_var,RANLIB,ranlib))
+-$(eval $(call override_var,STRIP,strip))
+-
+-RMDIR ?= rmdir
+-ECHO = /bin/echo -e
+-
+-ifeq ($(lastword $(subst /, ,$(CC))),clang)
+-CDRIVER = clang
+-else
+-CDRIVER = gcc
+-endif
+-
+-ifeq ($(lastword $(subst /, ,$(CXX))),clang++)
+-CXXDRIVER = clang
+-else
+-CXXDRIVER = gcc
+-endif
+-
+-# Internal macro to support check_XXX macros below.
+-# Usage: $(call check_compile, [code], [compiler], [code_type], [c_flags],
+-#               [extra_c_flags], [library_flags], [success_ret], [fail_ret])
+-# Return: [success_ret] if compile succeeded, otherwise [fail_ret]
+-check_compile = $(shell printf '%b\n' $(1) | \
+-  $($(2)) $($(4)) -x $(3) $(LDFLAGS) $(5) - $(6) -o /dev/null > /dev/null 2>&1 \
+-  && echo "$(7)" || echo "$(8)")
+-
+-# Helper macro to check whether a test program will compile with the specified
+-# compiler flags.
+-# Usage: $(call check_compile_cc, [code], [flags], [alternate_flags])
+-# Return: [flags] if compile succeeded, otherwise [alternate_flags]
+-check_compile_cc = $(call check_compile,$(1),CC,c,CFLAGS,$(2),,$(2),$(3))
+-check_compile_cxx = $(call check_compile,$(1),CXX,c++,CXXFLAGS,$(2),,$(2),$(3))
+-
+-# Helper macro to check whether a test program will compile with the specified
+-# libraries.
+-# Usage: $(call check_compile_cc, [code], [library_flags], [alternate_flags])
+-# Return: [library_flags] if compile succeeded, otherwise [alternate_flags]
+-check_libs_cc = $(call check_compile,$(1),CC,c,CFLAGS,,$(2),$(2),$(3))
+-check_libs_cxx = $(call check_compile,$(1),CXX,c++,CXXFLAGS,,$(2),$(2),$(3))
+-
+-# Helper macro to check whether the compiler accepts the specified flags.
+-# Usage: $(call check_compile_cc, [flags], [alternate_flags])
+-# Return: [flags] if compile succeeded, otherwise [alternate_flags]
+-check_cc = $(call check_compile_cc,'int main() { return 0; }',$(1),$(2))
+-check_cxx = $(call check_compile_cxx,'int main() { return 0; }',$(1),$(2))
+-
+-# Choose the stack protector flags based on whats supported by the compiler.
+-SSP_CFLAGS := $(call check_cc,-fstack-protector-strong)
+-ifeq ($(SSP_CFLAGS),)
+- SSP_CFLAGS := $(call check_cc,-fstack-protector-all)
+-endif
+-
+-# To update these from an including Makefile:
+-#  CXXFLAGS += -mahflag  # Append to the list
+-#  CXXFLAGS := -mahflag $(CXXFLAGS) # Prepend to the list
+-#  CXXFLAGS := $(filter-out badflag,$(CXXFLAGS)) # Filter out a value
+-# The same goes for CFLAGS.
+-COMMON_CFLAGS-gcc := -fvisibility=internal -ggdb3 -Wa,--noexecstack
+-COMMON_CFLAGS-clang := -fvisibility=hidden -ggdb
+-COMMON_CFLAGS := -Wall -Werror -fno-strict-aliasing $(SSP_CFLAGS) -O1 -Wformat=2
+-CXXFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CXXDRIVER))
+-CFLAGS += $(COMMON_CFLAGS) $(COMMON_CFLAGS-$(CDRIVER))
+-CPPFLAGS += -D_FORTIFY_SOURCE=2
+-
+-# Enable large file support.
+-CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+-
+-# Disable exceptions based on the CXXEXCEPTIONS setting.
+-ifeq ($(CXXEXCEPTIONS),0)
+-  CXXFLAGS := $(CXXFLAGS) -fno-exceptions -fno-unwind-tables \
+-    -fno-asynchronous-unwind-tables
+-endif
+-
+-ifeq ($(MODE),opt)
+-  # Up the optimizations.
+-  CFLAGS := $(filter-out -O1,$(CFLAGS)) -O2
+-  CXXFLAGS := $(filter-out -O1,$(CXXFLAGS)) -O2
+-  # Only drop -g* if symbols aren't desired.
+-  ifeq ($(NOSTRIP),0)
+-    # TODO: do we want -fomit-frame-pointer on x86?
+-    CFLAGS := $(filter-out -ggdb3,$(CFLAGS))
+-    CXXFLAGS := $(filter-out -ggdb3,$(CXXFLAGS))
+-  endif
+-endif
+-
+-ifeq ($(MODE),profiling)
+-  CFLAGS := $(CFLAGS) -O0 -g  --coverage
+-  CXXFLAGS := $(CXXFLAGS) -O0 -g  --coverage
+-  LDFLAGS := $(LDFLAGS) --coverage
+-endif
+-
+-LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,noexecstack -Wl,-z,now
+-
+-# Fancy helpers for color if a prompt is defined
+-ifeq ($(COLOR),1)
+-COLOR_RESET = \x1b[0m
+-COLOR_GREEN = \x1b[32;01m
+-COLOR_RED = \x1b[31;01m
+-COLOR_YELLOW = \x1b[33;01m
+-endif
+-
+-# By default, silence build output.
+-QUIET = @
+-ifeq ($(VERBOSE),1)
+-  QUIET=
+-endif
+-
+-#
+-# Implementation macros for compile helpers above
+-#
+-
+-# Useful for dealing with pie-broken toolchains.
+-# Call make with PIE=0 to disable default PIE use.
+-OBJ_PIE_FLAG = -fPIE
+-COMPILE_PIE_FLAG = -pie
+-ifeq ($(PIE),0)
+-  OBJ_PIE_FLAG =
+-  COMPILE_PIE_FLAG =
+-endif
+-
+-# Favor member targets first for CXX_BINARY(%) magic.
+-# And strip out nested members if possible.
+-LP := (
+-RP := )
+-TARGET_OR_MEMBER = $(lastword $(subst $(LP), ,$(subst $(RP),,$(or $%,$@))))
+-
+-# Default compile from objects using pre-requisites but filters out
+-# all non-.o files.
+-define COMPILE_BINARY_implementation
+-  @$(ECHO) "LD$(1)		$(subst $(PWD)/,,$(TARGET_OR_MEMBER))"
+-  $(call auto_mkdir,$(TARGET_OR_MEMBER))
+-  $(QUIET)$($(1)) $(COMPILE_PIE_FLAGS) -o $(TARGET_OR_MEMBER) \
+-    $(2) $(LDFLAGS) \
+-    $(filter %.o %.a,$(^:.o=.pie.o)) \
+-    $(foreach so,$(filter %.so,$^),-L$(dir $(so)) \
+-                            -l$(patsubst lib%,%,$(basename $(notdir $(so))))) \
+-    $(LDLIBS)
+-  $(call conditional_strip)
+-  @$(ECHO) -n "BIN		"
+-  @$(ECHO) "$(COLOR_GREEN)$(subst $(PWD)/,,$(TARGET_OR_MEMBER))$(COLOR_RESET)"
+-  @$(ECHO) "	$(COLOR_YELLOW)-----$(COLOR_RESET)"
+-endef
+-
+-# TODO: add version support extracted from PV environment variable
+-#ifeq ($(PV),9999)
+-#$(warning PV=$(PV). If shared object versions matter, please force PV=.)
+-#endif
+-# Then add -Wl,-soname,$@.$(PV) ?
+-
+-# Default compile from objects using pre-requisites but filters out
+-# all non-.o values. (Remember to add -L$(OUT) -llib)
+-COMMA := ,
+-define COMPILE_LIBRARY_implementation
+-  @$(ECHO) "SHARED$(1)	$(subst $(PWD)/,,$(TARGET_OR_MEMBER))"
+-  $(call auto_mkdir,$(TARGET_OR_MEMBER))
+-  $(QUIET)$($(1)) -shared -Wl,-E -o $(TARGET_OR_MEMBER) \
+-    $(2) $(LDFLAGS) \
+-    $(if $(filter %.a,$^),-Wl$(COMMA)--whole-archive,) \
+-    $(filter %.o ,$(^:.o=.pic.o)) \
+-    $(foreach a,$(filter %.a,$^),-L$(dir $(a)) \
+-                            -l$(patsubst lib%,%,$(basename $(notdir $(a))))) \
+-    $(foreach so,$(filter %.so,$^),-L$(dir $(so)) \
+-                            -l$(patsubst lib%,%,$(basename $(notdir $(so))))) \
+-    $(LDLIBS)
+-  $(call conditional_strip)
+-  @$(ECHO) -n "LIB		$(COLOR_GREEN)"
+-  @$(ECHO) "$(subst $(PWD)/,,$(TARGET_OR_MEMBER))$(COLOR_RESET)"
+-  @$(ECHO) "	$(COLOR_YELLOW)-----$(COLOR_RESET)"
+-endef
+-
+-define conditional_strip
+-  $(if $(filter 0,$(NOSTRIP)),$(call strip_artifact))
+-endef
+-
+-define strip_artifact
+-  @$(ECHO) "STRIP		$(subst $(OUT)/,,$(TARGET_OR_MEMBER))"
+-  $(if $(filter 1,$(SPLITDEBUG)), @$(ECHO) -n "DEBUG	"; \
+-    $(ECHO) "$(COLOR_YELLOW)\
+-$(subst $(OUT)/,,$(TARGET_OR_MEMBER)).debug$(COLOR_RESET)")
+-  $(if $(filter 1,$(SPLITDEBUG)), \
+-    $(QUIET)$(OBJCOPY) --only-keep-debug "$(TARGET_OR_MEMBER)" \
+-      "$(TARGET_OR_MEMBER).debug")
+-  $(if $(filter-out dbg,$(MODE)),$(QUIET)$(STRIP) --strip-unneeded \
+-    "$(TARGET_OR_MEMBER)",)
+-endef
+-
+-#
+-# Global pattern rules
+-#
+-
+-# Below, the archive member syntax is abused to create fancier
+-# syntactic sugar for recipe authors that avoids needed to know
+-# subcall options.  The downside is that make attempts to look
+-# into the phony archives for timestamps. This will cause the final
+-# target to be rebuilt/linked on _every_ call to make even when nothing
+-# has changed.  Until a better way presents itself, we have helpers that
+-# do the stat check on make's behalf.  Dodgy but simple.
+-define old_or_no_timestamp
+-  $(if $(realpath $%),,$(1))
+-  $(if $(shell find $^ -cnewer "$%" 2>/dev/null),$(1))
+-endef
+-
+-define check_deps
+-  $(if $(filter 0,$(words $^)),\
+-    $(error Missing dependencies or declaration of $@($%)),)
+-endef
+-
+-# Build a cxx target magically
+-CXX_BINARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call cxx_binary))
+-clean: CLEAN(CXX_BINARY*)
+-
+-CC_BINARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call cc_binary))
+-clean: CLEAN(CC_BINARY*)
+-
+-CXX_STATIC_BINARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call cxx_binary,-static))
+-clean: CLEAN(CXX_STATIC_BINARY*)
+-
+-CC_STATIC_BINARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call cc_binary,-static))
+-clean: CLEAN(CC_STATIC_BINARY*)
+-
+-CXX_LIBRARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call cxx_library))
+-clean: CLEAN(CXX_LIBRARY*)
+-
+-CXX_LIBARY(%):
+-	$(error Typo alert! LIBARY != LIBRARY)
+-
+-CC_LIBRARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call cc_library))
+-clean: CLEAN(CC_LIBRARY*)
+-
+-CC_LIBARY(%):
+-	$(error Typo alert! LIBARY != LIBRARY)
+-
+-CXX_STATIC_LIBRARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call update_archive))
+-clean: CLEAN(CXX_STATIC_LIBRARY*)
+-
+-CXX_STATIC_LIBARY(%):
+-	$(error Typo alert! LIBARY != LIBRARY)
+-
+-CC_STATIC_LIBRARY(%):
+-	$(call check_deps)
+-	$(call old_or_no_timestamp,$(call update_archive))
+-clean: CLEAN(CC_STATIC_LIBRARY*)
+-
+-CC_STATIC_LIBARY(%):
+-	$(error Typo alert! LIBARY != LIBRARY)
+-
+-
+-TEST(%): % qemu_chroot_install
+-	$(call TEST_implementation)
+-.PHONY: TEST
+-
+-# multiple targets with a wildcard need to share an directory.
+-# Don't use this directly it just makes sure the directory is removed _after_
+-# the files are.
+-CLEANFILE(%):
+-	$(call silent_rm,$(TARGET_OR_MEMBER))
+-.PHONY: CLEANFILE
+-
+-CLEAN(%): CLEANFILE(%)
+-	$(QUIET)# CLEAN($%) meta-target called
+-	$(if $(filter-out $(PWD)/,$(dir $(abspath $(TARGET_OR_MEMBER)))), \
+-	  $(call silent_rmdir,$(dir $(abspath $(TARGET_OR_MEMBER)))),\
+-	  $(QUIET)# Not deleting $(dir $(abspath $(TARGET_OR_MEMBER))) yet.)
+-.PHONY: CLEAN
+-
+-#
+-# Top-level objects and pattern rules
+-#
+-
+-# All objects for .c files at the top level
+-C_OBJECTS = $(patsubst $(SRC)/%.c,%.o,$(wildcard $(SRC)/*.c))
+-
+-
+-# All objects for .cxx files at the top level
+-CXX_OBJECTS = $(patsubst $(SRC)/%.cc,%.o,$(wildcard $(SRC)/*.cc))
+-
+-# Note, the catch-all pattern rules don't work in subdirectories because
+-# we're building from the $(OUT) directory. At the top-level (here) they will
+-# work, but we go ahead and match using the module form.  Then we can place a
+-# generic pattern rule to capture leakage from the main Makefile. (Later in the
+-# file.)
+-#
+-# The reason target specific pattern rules work well for modules,
+-# MODULE_C_OBJECTS, is because it scopes the behavior to the given target which
+-# ensures we get a relative directory offset from $(OUT) which otherwise would
+-# not match without further magic on a per-subdirectory basis.
+-
+-# Creates object file rules. Call with eval.
+-# $(1) list of .o files
+-# $(2) source type (CC or CXX)
+-# $(3) source suffix (cc or c)
+-# $(4) compiler flag name (CFLAGS or CXXFLAGS)
+-# $(5) source dir: _only_ if $(SRC). Leave blank for obj tree.
+-define add_object_rules
+-$(patsubst %.o,%.pie.o,$(1)): %.pie.o: $(5)%.$(3) %.o.depends
+-	$$(call auto_mkdir,$$@)
+-	$$(call OBJECT_PATTERN_implementation,$(2),\
+-          $$(basename $$@),$$($(4)) $$(CPPFLAGS) $$(OBJ_PIE_FLAG))
+-
+-$(patsubst %.o,%.pic.o,$(1)): %.pic.o: $(5)%.$(3) %.o.depends
+-	$$(call auto_mkdir,$$@)
+-	$$(call OBJECT_PATTERN_implementation,$(2),\
+-          $$(basename $$@),$$($(4)) $$(CPPFLAGS) -fPIC)
+-
+-# Placeholder for depends
+-$(patsubst %.o,%.o.depends,$(1)):
+-	$$(call auto_mkdir,$$@)
+-	$$(QUIET)touch "$$@"
+-
+-$(1): %.o: %.pic.o %.pie.o
+-	$$(call auto_mkdir,$$@)
+-	$$(QUIET)touch "$$@"
+-endef
+-
+-define OBJECT_PATTERN_implementation
+-  @$(ECHO) "$(1)		$(subst $(SRC)/,,$<) -> $(2).o"
+-  $(call auto_mkdir,$@)
+-  $(QUIET)$($(1)) -c -MD -MF $(2).d $(3) -o $(2).o $<
+-  $(QUIET)# Wrap all the deps in $$(wildcard) so a missing header
+-  $(QUIET)# won't cause weirdness.  First we remove newlines and \,
+-  $(QUIET)# then wrap it.
+-  $(QUIET)sed -i -e :j -e '$$!N;s|\\\s*\n| |;tj' \
+-    -e 's|^\(.*\s*:\s*\)\(.*\)$$|\1 $$\(wildcard \2\)|' $(2).d
+-endef
+-
+-# Now actually register handlers for C(XX)_OBJECTS.
+-$(eval $(call add_object_rules,$(C_OBJECTS),CC,c,CFLAGS,$(SRC)/))
+-$(eval $(call add_object_rules,$(CXX_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+-
+-# Disable default pattern rules to help avoid leakage.
+-# These may already be handled by '-r', but let's keep it to be safe.
+-%: %.o ;
+-%.a: %.o ;
+-%.o: %.c ;
+-%.o: %.cc ;
+-
+-# NOTE: A specific rule for archive objects is avoided because parallel
+-#       update of the archive causes build flakiness.
+-# Instead, just make the objects the prerequisites and use update_archive
+-# To use the foo.a(obj.o) functionality, targets would need to specify the
+-# explicit object they expect on the prerequisite line.
+-
+-#
+-# Architecture detection and QEMU wrapping
+-#
+-
+-HOST_ARCH ?= $(shell uname -m)
+-override ARCH := $(strip $(ARCH))
+-override HOST_ARCH := $(strip $(HOST_ARCH))
+-# emake will supply "x86" or "arm" for ARCH, but
+-# if uname -m runs and you get x86_64, then this subst
+-# will break.
+-ifeq ($(subst x86,i386,$(ARCH)),i386)
+-  QEMU_ARCH := $(subst x86,i386,$(ARCH))  # x86 -> i386
+-else ifeq ($(subst amd64,x86_64,$(ARCH)),x86_64)
+-  QEMU_ARCH := $(subst amd64,x86_64,$(ARCH))  # amd64 -> x86_64
+-else
+-  QEMU_ARCH = $(ARCH)
+-endif
+-override QEMU_ARCH := $(strip $(QEMU_ARCH))
+-
+-# If we're cross-compiling, try to use qemu for running the tests.
+-ifneq ($(QEMU_ARCH),$(HOST_ARCH))
+-  ifeq ($(SYSROOT),)
+-    $(info SYSROOT not defined. qemu-based testing disabled)
+-  else
+-    # A SYSROOT is assumed for QEmu use.
+-    USE_QEMU ?= 1
+-
+-    # Allow 64-bit hosts to run 32-bit without qemu.
+-    ifeq ($(HOST_ARCH),x86_64)
+-      ifeq ($(QEMU_ARCH),i386)
+-        USE_QEMU = 0
+-      endif
+-    endif
+-  endif
+-else
+-  USE_QEMU ?= 0
+-endif
+-
+-# Normally we don't need to run as root or do bind mounts, so only
+-# enable it by default when we're using QEMU.
+-NEEDS_ROOT ?= $(USE_QEMU)
+-NEEDS_MOUNTS ?= $(USE_QEMU)
+-
+-SYSROOT_OUT = $(OUT)
+-ifneq ($(SYSROOT),)
+-  SYSROOT_OUT = $(subst $(SYSROOT),,$(OUT))
+-else
+-  # Default to / when all the empty-sysroot logic is done.
+-  SYSROOT = /
+-endif
+-
+-QEMU_NAME = qemu-$(QEMU_ARCH)
+-QEMU_PATH = /build/bin/$(QEMU_NAME)
+-QEMU_SYSROOT_PATH = $(SYSROOT)$(QEMU_PATH)
+-QEMU_SRC_PATH = /usr/bin/$(QEMU_NAME)
+-QEMU_BINFMT_PATH = /proc/sys/fs/binfmt_misc/$(QEMU_NAME)
+-QEMU_REGISTER_PATH = /proc/sys/fs/binfmt_misc/register
+-
+-QEMU_MAGIC_arm = ":$(QEMU_NAME):M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/build/bin/qemu-arm:"
+-
+-
+-#
+-# Output full configuration at top level
+-#
+-
+-# Don't show on clean
+-ifneq ($(MAKECMDGOALS),clean)
+-  $(info build configuration:)
+-  $(info - OUT=$(OUT))
+-  $(info - SRC=$(SRC))
+-  $(info - MODE=$(MODE))
+-  $(info - SPLITDEBUG=$(SPLITDEBUG))
+-  $(info - NOSTRIP=$(NOSTRIP))
+-  $(info - VALGRIND=$(VALGRIND))
+-  $(info - COLOR=$(COLOR))
+-  $(info - CXXEXCEPTIONS=$(CXXEXCEPTIONS))
+-  $(info - ARCH=$(ARCH))
+-  $(info - QEMU_ARCH=$(QEMU_ARCH))
+-  $(info - USE_QEMU=$(USE_QEMU))
+-  $(info - NEEDS_ROOT=$(NEEDS_ROOT))
+-  $(info - NEEDS_MOUNTS=$(NEEDS_MOUNTS))
+-  $(info - SYSROOT=$(SYSROOT))
+-  $(info )
+-endif
+-
+-#
+-# Standard targets with detection for when they are improperly configured.
+-#
+-
+-# all does not include tests by default
+-all:
+-	$(QUIET)(test -z "$^" && \
+-	$(ECHO) "You must add your targets as 'all' prerequisites") || true
+-	$(QUIET)test -n "$^"
+-
+-# Builds and runs tests for the target arch
+-# Run them in parallel
+-# After the test have completed, if profiling, run coverage analysis
+-tests:
+-ifeq ($(MODE),profiling)
+-	@$(ECHO) "COVERAGE [$(COLOR_YELLOW)STARTED$(COLOR_RESET)]"
+-	$(QUIET)FILES="";						\
+-		for GCNO in `find . -name "*.gcno"`; do			\
+-			GCDA="$${GCNO%.gcno}.gcda";			\
+-			if [ -e $${GCDA} ]; then			\
+-				FILES="$${FILES} $${GCDA}";		\
+-			fi						\
+-		done;							\
+-		if [ -n "$${FILES}" ]; then				\
+-			gcov -l $${FILES};				\
+-			lcov --capture --directory .			\
+-				--output-file=lcov-coverage.info;	\
+-			genhtml lcov-coverage.info			\
+-				--output-directory lcov-html;		\
+-		fi
+-	@$(ECHO) "COVERAGE [$(COLOR_YELLOW)FINISHED$(COLOR_RESET)]"
+-endif
+-.PHONY: tests
+-
+-qemu_chroot_install:
+-ifeq ($(USE_QEMU),1)
+-	$(QUIET)$(ECHO) "QEMU   Preparing $(QEMU_NAME)"
+-	@# Copying strategy
+-	@# Compare /usr/bin/qemu inode to /build/$board/build/bin/qemu, if different
+-	@# hard link to a temporary file, then rename temp to target. This should
+-	@# ensure that once $QEMU_SYSROOT_PATH exists it will always exist, regardless
+-	@# of simultaneous test setups.
+-	$(QUIET)if [[ ! -e $(QEMU_SYSROOT_PATH) || \
+-	    `stat -c %i $(QEMU_SRC_PATH)` != `stat -c %i $(QEMU_SYSROOT_PATH)` \
+-	    ]]; then \
+-	  $(ROOT_CMD) ln -Tf $(QEMU_SRC_PATH) $(QEMU_SYSROOT_PATH).$$$$; \
+-	  $(ROOT_CMD) mv -Tf $(QEMU_SYSROOT_PATH).$$$$ $(QEMU_SYSROOT_PATH); \
+-	fi
+-
+-	@# Prep the binfmt handler. First mount if needed, then unregister any bad
+-	@# mappings and then register our mapping.
+-	@# There may still be some race conditions here where one script de-registers
+-	@# and another script starts executing before it gets re-registered, however
+-	@# it should be rare.
+-	-$(QUIET)[[ -e $(QEMU_REGISTER_PATH) ]] || \
+-	  $(ROOT_CMD) mount binfmt_misc -t binfmt_misc \
+-	    /proc/sys/fs/binfmt_misc
+-
+-	-$(QUIET)if [[ -e $(QEMU_BINFMT_PATH) && \
+-	      `awk '$$1 == "interpreter" {print $$NF}' $(QEMU_BINFMT_PATH)` != \
+-	      "$(QEMU_PATH)" ]]; then \
+-	  echo -1 | $(ROOT_CMD) tee $(QEMU_BINFMT_PATH) >/dev/null; \
+-	fi
+-
+-	-$(if $(QEMU_MAGIC_$(ARCH)),$(QUIET)[[ -e $(QEMU_BINFMT_PATH) ]] || \
+-	  echo $(QEMU_MAGIC_$(ARCH)) | $(ROOT_CMD) tee $(QEMU_REGISTER_PATH) \
+-	    >/dev/null)
+-endif
+-.PHONY: qemu_clean qemu_chroot_install
+-
+-# TODO(wad) Move to -L $(SYSROOT) and fakechroot when qemu-user
+-#           doesn't hang traversing /proc from SYSROOT.
+-SUDO_CMD = sudo
+-UNSHARE_CMD = unshare
+-QEMU_CMD =
+-ROOT_CMD = $(if $(filter 1,$(NEEDS_ROOT)),$(SUDO_CMD) , )
+-MOUNT_CMD = $(if $(filter 1,$(NEEDS_MOUNTS)),$(ROOT_CMD) mount, \#)
+-UMOUNT_CMD = $(if $(filter 1,$(NEEDS_MOUNTS)),$(ROOT_CMD) umount, \#)
+-QEMU_LDPATH = $(SYSROOT_LDPATH):/lib64:/lib:/usr/lib64:/usr/lib
+-ROOT_CMD_LDPATH = $(SYSROOT_LDPATH):$(SYSROOT)/lib64:
+-ROOT_CMD_LDPATH := $(ROOT_CMD_LDPATH):$(SYSROOT)/lib:$(SYSROOT)/usr/lib64:
+-ROOT_CMD_LDPATH := $(ROOT_CMD_LDPATH):$(SYSROOT)/usr/lib
+-ifeq ($(USE_QEMU),1)
+-  export QEMU_CMD = \
+-   $(SUDO_CMD) chroot $(SYSROOT) $(QEMU_PATH) \
+-   -drop-ld-preload \
+-   -E LD_LIBRARY_PATH="$(QEMU_LDPATH):$(patsubst $(OUT),,$(LD_DIRS))" \
+-   -E HOME="$(HOME)" -E SRC="$(SRC)" --
+-  # USE_QEMU conditional function
+-  define if_qemu
+-    $(1)
+-  endef
+-else
+-  ROOT_CMD = $(if $(filter 1,$(NEEDS_ROOT)),sudo, ) \
+-    LD_LIBRARY_PATH="$(ROOT_CMD_LDPATH):$(LD_DIRS)"
+-  define if_qemu
+-    $(2)
+-  endef
+-endif
+-
+-VALGRIND_CMD =
+-ifeq ($(VALGRIND),1)
+-  VALGRIND_CMD = /usr/bin/valgrind --tool=memcheck $(VALGRIND_ARGS) --
+-endif
+-
+-define TEST_implementation
+-  $(QUIET)$(call TEST_setup)
+-  $(QUIET)$(call TEST_run)
+-  $(QUIET)$(call TEST_teardown)
+-  $(QUIET)exit $$(cat $(OUT)$(TARGET_OR_MEMBER).status.test)
+-endef
+-
+-define TEST_setup
+-  @$(ECHO) -n "TEST		$(TARGET_OR_MEMBER) "
+-  @$(ECHO) "[$(COLOR_YELLOW)SETUP$(COLOR_RESET)]"
+-  $(QUIET)# Setup a target-specific results file
+-  $(QUIET)(echo > $(OUT)$(TARGET_OR_MEMBER).setup.test)
+-  $(QUIET)(echo 1 > $(OUT)$(TARGET_OR_MEMBER).status.test)
+-  $(QUIET)(echo > $(OUT)$(TARGET_OR_MEMBER).cleanup.test)
+-  $(QUIET)# No setup if we are not using QEMU
+-  $(QUIET)# TODO(wad) this is racy until we use a vfs namespace
+-  $(call if_qemu,\
+-    $(QUIET)(echo "mkdir -p '$(SYSROOT)/proc' '$(SYSROOT)/dev' \
+-                            '$(SYSROOT)/mnt/host/source'" \
+-             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+-  $(call if_qemu,\
+-    $(QUIET)(echo "$(MOUNT_CMD) --bind /mnt/host/source \
+-             '$(SYSROOT)/mnt/host/source'" \
+-             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+-  $(call if_qemu,\
+-    $(QUIET)(echo "$(MOUNT_CMD) --bind /proc '$(SYSROOT)/proc'" \
+-             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+-  $(call if_qemu,\
+-    $(QUIET)(echo "$(MOUNT_CMD) --bind /dev '$(SYSROOT)/dev'" \
+-             >> "$(OUT)$(TARGET_OR_MEMBER).setup.test"))
+-endef
+-
+-define TEST_teardown
+-  @$(ECHO) -n "TEST		$(TARGET_OR_MEMBER) "
+-  @$(ECHO) "[$(COLOR_YELLOW)TEARDOWN$(COLOR_RESET)]"
+-  $(call if_qemu, $(QUIET)$(SHELL) "$(OUT)$(TARGET_OR_MEMBER).cleanup.test")
+-endef
+-
+-# Use GTEST_ARGS.[arch] if defined.
+-override GTEST_ARGS.real = \
+- $(call if_qemu,$(GTEST_ARGS.qemu.$(QEMU_ARCH)),$(GTEST_ARGS.host.$(HOST_ARCH)))
+-
+-define TEST_run
+-  @$(ECHO) -n "TEST		$(TARGET_OR_MEMBER) "
+-  @$(ECHO) "[$(COLOR_GREEN)RUN$(COLOR_RESET)]"
+-  $(QUIET)(echo 1 > "$(OUT)$(TARGET_OR_MEMBER).status.test")
+-  $(QUIET)(echo $(ROOT_CMD) SRC="$(SRC)" $(QEMU_CMD) $(VALGRIND_CMD) \
+-    "$(strip $(call if_qemu, $(SYSROOT_OUT),$(OUT))$(TARGET_OR_MEMBER))" \
+-      $(if $(filter-out 0,$(words $(GTEST_ARGS.real))),$(GTEST_ARGS.real),\
+-           $(GTEST_ARGS)) >> "$(OUT)$(TARGET_OR_MEMBER).setup.test")
+-  -$(QUIET)$(call if_qemu,$(SUDO_CMD) $(UNSHARE_CMD) -m) $(SHELL) \
+-      $(OUT)$(TARGET_OR_MEMBER).setup.test \
+-  && echo 0 > "$(OUT)$(TARGET_OR_MEMBER).status.test"
+-endef
+-
+-# Recursive list reversal so that we get RMDIR_ON_CLEAN in reverse order.
+-define reverse
+-$(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1))
+-endef
+-
+-clean: qemu_clean
+-clean: CLEAN($(OUT)*.d) CLEAN($(OUT)*.o) CLEAN($(OUT)*.debug)
+-clean: CLEAN($(OUT)*.test) CLEAN($(OUT)*.depends)
+-clean: CLEAN($(OUT)*.gcno) CLEAN($(OUT)*.gcda) CLEAN($(OUT)*.gcov)
+-clean: CLEAN($(OUT)lcov-coverage.info) CLEAN($(OUT)lcov-html)
+-
+-clean:
+-	$(QUIET)# Always delete the containing directory last.
+-	$(call silent_rmdir,$(OUT))
+-
+-FORCE: ;
+-# Empty rule for use when no special targets are needed, like large_tests
+-NONE:
+-
+-.PHONY: clean NONE valgrind NONE
+-.DEFAULT_GOAL  :=  all
+-# Don't let make blow away "intermediates"
+-.PRECIOUS: %.pic.o %.pie.o %.a %.pic.a %.pie.a %.test
+-
+-# Start accruing build info
+-OUT_DIRS = $(OUT)
+-LD_DIRS = $(OUT)
+-SRC_DIRS = $(SRC)
+-
+-include $(wildcard $(OUT)*.d)
+-SUBMODULE_DIRS = $(wildcard $(SRC)/*/module.mk)
+-include $(SUBMODULE_DIRS)
+-
+-
+-else  ## In duplicate inclusions of common.mk
+-
+-# Get the current inclusion directory without a trailing slash
+-MODULE := $(patsubst %/,%, \
+-           $(dir $(lastword $(filter-out %common.mk,$(MAKEFILE_LIST)))))
+-MODULE := $(subst $(SRC)/,,$(MODULE))
+-MODULE_NAME := $(subst /,_,$(MODULE))
+-#VPATH := $(MODULE):$(VPATH)
+-
+-
+-# Depth first
+-$(eval OUT_DIRS += $(OUT)$(MODULE))
+-$(eval SRC_DIRS += $(OUT)$(MODULE))
+-$(eval LD_DIRS := $(LD_DIRS):$(OUT)$(MODULE))
+-
+-# Add the defaults from this dir to rm_clean
+-clean: CLEAN($(OUT)$(MODULE)/*.d) CLEAN($(OUT)$(MODULE)/*.o)
+-clean: CLEAN($(OUT)$(MODULE)/*.debug) CLEAN($(OUT)$(MODULE)/*.test)
+-clean: CLEAN($(OUT)$(MODULE)/*.depends)
+-clean: CLEAN($(OUT)$(MODULE)/*.gcno) CLEAN($(OUT)$(MODULE)/*.gcda)
+-clean: CLEAN($(OUT)$(MODULE)/*.gcov) CLEAN($(OUT)lcov-coverage.info)
+-clean: CLEAN($(OUT)lcov-html)
+-
+-$(info + submodule: $(MODULE_NAME))
+-# We must eval otherwise they may be dropped.
+-MODULE_C_OBJECTS = $(patsubst $(SRC)/$(MODULE)/%.c,$(MODULE)/%.o,\
+-  $(wildcard $(SRC)/$(MODULE)/*.c))
+-$(eval $(MODULE_NAME)_C_OBJECTS ?= $(MODULE_C_OBJECTS))
+-MODULE_CXX_OBJECTS = $(patsubst $(SRC)/$(MODULE)/%.cc,$(MODULE)/%.o,\
+-  $(wildcard $(SRC)/$(MODULE)/*.cc))
+-$(eval $(MODULE_NAME)_CXX_OBJECTS ?= $(MODULE_CXX_OBJECTS))
+-
+-# Note, $(MODULE) is implicit in the path to the %.c.
+-# See $(C_OBJECTS) for more details.
+-# Register rules for the module objects.
+-$(eval $(call add_object_rules,$(MODULE_C_OBJECTS),CC,c,CFLAGS,$(SRC)/))
+-$(eval $(call add_object_rules,$(MODULE_CXX_OBJECTS),CXX,cc,CXXFLAGS,$(SRC)/))
+-
+-# Continue recursive inclusion of module.mk files
+-SUBMODULE_DIRS = $(wildcard $(SRC)/$(MODULE)/*/module.mk)
+-include $(wildcard $(OUT)$(MODULE)/*.d)
+-include $(SUBMODULE_DIRS)
+-
+-endif
+-endif  ## pass-to-subcall wrapper for relocating the call directory
+diff --git a/fuzzers/modp_b64_decode_fuzzer.cc b/fuzzers/modp_b64_decode_fuzzer.cc
+new file mode 100644
+index 0000000..176ebc3
+--- /dev/null
++++ b/fuzzers/modp_b64_decode_fuzzer.cc
+@@ -0,0 +1,17 @@
++// Copyright 2019 The Chromium OS Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include <string>
++#include <cstddef>
++#include <cstdint>
++
++#include "modp_b64.h"
++
++extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
++  // Create a buffer to store the output.
++  std::string buffer;
++  buffer.resize(modp_b64_decode_len(size));
++  modp_b64_decode(&(buffer[0]), (const char *) data, size);
++  return 0;
++}
+diff --git a/fuzzers/modp_b64_encode_fuzzer.cc b/fuzzers/modp_b64_encode_fuzzer.cc
+new file mode 100644
+index 0000000..0f61575
+--- /dev/null
++++ b/fuzzers/modp_b64_encode_fuzzer.cc
+@@ -0,0 +1,17 @@
++// Copyright 2019 The Chromium OS Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include <string>
++#include <cstddef>
++#include <cstdint>
++
++#include "modp_b64.h"
++
++extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
++  // Create a buffer to store the output.
++  std::string buffer;
++  buffer.resize(modp_b64_encode_len(size));
++  modp_b64_encode(&buffer[0], (const char *)data, size);
++  return 0;
++}
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/modp_b64/0002-Use-regular-archives.patch b/pkgs/os-specific/linux/chromium-os/modp_b64/0002-Use-regular-archives.patch
new file mode 100644
index 00000000000..57f087d5b16
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modp_b64/0002-Use-regular-archives.patch
@@ -0,0 +1,36 @@
+From 11a6fc258c6765a43b973b15e86fb4bce7675202 Mon Sep 17 00:00:00 2001
+From: Manoj Gupta <manojgupta@google.com>
+Date: Mon, 14 Oct 2019 11:37:20 -0700
+Subject: [PATCH 2/2] Use regular archives.
+
+libmodp_b64 needs to be linked by libchrome later so
+use regular archives.
+
+BUG=chromium:1012803
+TEST=libchrome can link with libmodp_b64.
+
+Change-Id: Ie0bbcc8a54051d4136463c95762ba8343e487862
+---
+ BUILD.gn | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/BUILD.gn b/BUILD.gn
+index b2fe97d..9107609 100644
+--- a/BUILD.gn
++++ b/BUILD.gn
+@@ -16,6 +16,12 @@ group("all") {
+ }
+ 
+ static_library("modp_b64") {
++  configs -= [
++    "//common-mk:use_thin_archive",
++  ]
++  configs += [
++    "//common-mk:nouse_thin_archive",
++  ]
+   sources = [
+     "modp_b64.cc",
+     "modp_b64.h",
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/modp_b64/default.nix b/pkgs/os-specific/linux/chromium-os/modp_b64/default.nix
new file mode 100644
index 00000000000..4908443f9b7
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/modp_b64/default.nix
@@ -0,0 +1,30 @@
+{ common-mk, lib, fetchFromGitiles, upstreamInfo }:
+
+common-mk {
+  platformSubdir = "modp_b64";
+
+  src = fetchFromGitiles upstreamInfo.components."aosp/platform/external/modp_b64";
+
+  patches = [
+    # We could just use the Makefile, but it's going to be removed in
+    # the next release anyway so let's just get on the GN train early.
+    ./0001-modp_b64-Fix-GN-build-and-add-fuzzers.patch
+    ./0002-Use-regular-archives.patch
+  ];
+
+  installPhase = ''
+    mkdir -p $out/lib
+    install -m 0644 libmodp_b64.a $out/lib
+
+    mkdir $out/include
+    cp -r ../../modp_b64/modp_b64 $out/include
+  '';
+
+  meta = with lib; {
+    description = "High performance base64 encoder/decoder";
+    homepage = "https://github.com/client9/stringencoders";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ qyliss ];
+    platform = platforms.all;
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/protofiles/default.nix b/pkgs/os-specific/linux/chromium-os/protofiles/default.nix
new file mode 100644
index 00000000000..de8ecbb6963
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/protofiles/default.nix
@@ -0,0 +1,34 @@
+{ stdenv, lib, fetchFromGitiles, chromiumos-overlay, python2 }:
+
+stdenv.mkDerivation rec {
+  pname = "protofiles";
+  version = "0.0.36";
+
+  src = fetchFromGitiles {
+    url = "https://chromium.googlesource.com/chromium/src/components/policy";
+    rev = "72e354e16600a8999c85528147dcf762f31a4b78";
+    sha256 = "11v7n8d0ma426ba3i6q82k0vj0m5l1hx49waffivplpn0c92bm94";
+  };
+
+  buildInputs = [ python2 ];
+
+  installPhase = ''
+    mkdir -p $out/include/proto $out/share/protofiles \
+        $out/share/policy_resources $out/share/policy_tools
+
+    install -m 0644 proto/*.proto $out/include/proto
+    ln -s $out/include/proto/*.proto $out/share/protofiles
+    install -m 0644 resources/policy_templates.json $out/share/policy_resources
+    install -m 0644 ${chromiumos-overlay}/chromeos-base/protofiles/files/VERSION \
+      $out/share/policy_resources
+
+    install tools/generate_policy_source.py $out/share/policy_tools
+  '';
+
+  meta = with lib; {
+    inherit (src.meta) homepage;
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ qyliss ];
+    platform = platforms.all;
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/sommelier/0010-sommelier-don-t-leak-source-absolute-paths.patch b/pkgs/os-specific/linux/chromium-os/sommelier/0010-sommelier-don-t-leak-source-absolute-paths.patch
new file mode 100644
index 00000000000..a9f2df3b73e
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/sommelier/0010-sommelier-don-t-leak-source-absolute-paths.patch
@@ -0,0 +1,25 @@
+From b1a89637c458ea70ea0d280f1c2c469e177bfc6f Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <hi@alyssa.is>
+Date: Sun, 1 Dec 2019 17:04:04 +0000
+Subject: [PATCH 10/11] sommelier: don't leak source-absolute paths
+
+---
+ vm_tools/sommelier/wayland_protocol.gni | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/vm_tools/sommelier/wayland_protocol.gni b/vm_tools/sommelier/wayland_protocol.gni
+index 4f18a0c10..b1bd5d659 100644
+--- a/vm_tools/sommelier/wayland_protocol.gni
++++ b/vm_tools/sommelier/wayland_protocol.gni
+@@ -44,7 +44,7 @@ template("wayland_protocol_library") {
+         "wayland-scanner",
+         g.subcommand,
+         "{{source}}",
+-        output_file,
++        rebase_path(output_file),
+       ]
+     }
+   }
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/sommelier/0011-sommelier-use-stable-xdg-shell-protocol.patch b/pkgs/os-specific/linux/chromium-os/sommelier/0011-sommelier-use-stable-xdg-shell-protocol.patch
new file mode 100644
index 00000000000..b72d5c7c588
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/sommelier/0011-sommelier-use-stable-xdg-shell-protocol.patch
@@ -0,0 +1,1749 @@
+From f2655b38379414312efda57d6c0fdb73492fcab6 Mon Sep 17 00:00:00 2001
+From: Puck Meerburg <puck@puckipedia.com>
+Date: Tue, 3 Dec 2019 18:06:14 +0000
+Subject: [PATCH 11/11] sommelier: use stable xdg-shell protocol
+
+From https://github.com/wayland-project/weston/commit/d8d9f5e6e16c8f6a3c06763d5f56c27dc9a6e52e:
+
+> Some clients like the mpv video player now request the xdg_shell
+> protocol so these will fail if the compositor only provides the
+> xdg_shell_unstable_v6 protocol. Compositors like mir and gnome provide
+> both protocols.
+---
+ vm_tools/sommelier/BUILD.gn                   |   2 +-
+ ...dg-shell-unstable-v6.xml => xdg-shell.xml} | 319 ++++++++++++------
+ vm_tools/sommelier/sommelier-xdg-shell.c      | 242 ++++++-------
+ vm_tools/sommelier/sommelier.c                | 209 ++++++------
+ vm_tools/sommelier/sommelier.h                |  17 +-
+ 5 files changed, 450 insertions(+), 339 deletions(-)
+ rename vm_tools/sommelier/protocol/{xdg-shell-unstable-v6.xml => xdg-shell.xml} (79%)
+
+diff --git a/vm_tools/sommelier/BUILD.gn b/vm_tools/sommelier/BUILD.gn
+index 72d5c1647..f01655010 100644
+--- a/vm_tools/sommelier/BUILD.gn
++++ b/vm_tools/sommelier/BUILD.gn
+@@ -67,7 +67,7 @@ wayland_protocol_library("sommelier-protocol") {
+     "protocol/relative-pointer-unstable-v1.xml",
+     "protocol/text-input-unstable-v1.xml",
+     "protocol/viewporter.xml",
+-    "protocol/xdg-shell-unstable-v6.xml",
++    "protocol/xdg-shell.xml",
+   ]
+ }
+ 
+diff --git a/vm_tools/sommelier/protocol/xdg-shell-unstable-v6.xml b/vm_tools/sommelier/protocol/xdg-shell.xml
+similarity index 79%
+rename from vm_tools/sommelier/protocol/xdg-shell-unstable-v6.xml
+rename to vm_tools/sommelier/protocol/xdg-shell.xml
+index 1c0f92452..3a87a9ed6 100644
+--- a/vm_tools/sommelier/protocol/xdg-shell-unstable-v6.xml
++++ b/vm_tools/sommelier/protocol/xdg-shell.xml
+@@ -1,11 +1,13 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+-<protocol name="xdg_shell_unstable_v6">
++<protocol name="xdg_shell">
+ 
+   <copyright>
+     Copyright © 2008-2013 Kristian Høgsberg
+     Copyright © 2013      Rafael Antognolli
+     Copyright © 2013      Jasper St. Pierre
+     Copyright © 2010-2013 Intel Corporation
++    Copyright © 2015-2017 Samsung Electronics Co., Ltd
++    Copyright © 2015-2017 Red Hat Inc.
+ 
+     Permission is hereby granted, free of charge, to any person obtaining a
+     copy of this software and associated documentation files (the "Software"),
+@@ -27,18 +29,19 @@
+     DEALINGS IN THE SOFTWARE.
+   </copyright>
+ 
+-  <interface name="zxdg_shell_v6" version="1">
++  <interface name="xdg_wm_base" version="2">
+     <description summary="create desktop-style surfaces">
+-      xdg_shell allows clients to turn a wl_surface into a "real window"
+-      which can be dragged, resized, stacked, and moved around by the
+-      user. Everything about this interface is suited towards traditional
+-      desktop environments.
++      The xdg_wm_base interface is exposed as a global object enabling clients
++      to turn their wl_surfaces into windows in a desktop environment. It
++      defines the basic functionality needed for clients and the compositor to
++      create windows that can be dragged, resized, maximized, etc, as well as
++      creating transient windows such as popup menus.
+     </description>
+ 
+     <enum name="error">
+       <entry name="role" value="0" summary="given wl_surface has another role"/>
+       <entry name="defunct_surfaces" value="1"
+-	     summary="xdg_shell was destroyed before children"/>
++	     summary="xdg_wm_base was destroyed before children"/>
+       <entry name="not_the_topmost_popup" value="2"
+ 	     summary="the client tried to map or destroy a non-topmost popup"/>
+       <entry name="invalid_popup_parent" value="3"
+@@ -50,11 +53,11 @@
+     </enum>
+ 
+     <request name="destroy" type="destructor">
+-      <description summary="destroy xdg_shell">
+-	Destroy this xdg_shell object.
++      <description summary="destroy xdg_wm_base">
++	Destroy this xdg_wm_base object.
+ 
+-	Destroying a bound xdg_shell object while there are surfaces
+-	still alive created by this xdg_shell object instance is illegal
++	Destroying a bound xdg_wm_base object while there are surfaces
++	still alive created by this xdg_wm_base object instance is illegal
+ 	and will result in a protocol error.
+       </description>
+     </request>
+@@ -65,7 +68,7 @@
+ 	surfaces relative to some parent surface. See the interface description
+ 	and xdg_surface.get_popup for details.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_positioner_v6"/>
++      <arg name="id" type="new_id" interface="xdg_positioner"/>
+     </request>
+ 
+     <request name="get_xdg_surface">
+@@ -82,14 +85,14 @@
+ 	See the documentation of xdg_surface for more details about what an
+ 	xdg_surface is and how it is used.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_surface_v6"/>
++      <arg name="id" type="new_id" interface="xdg_surface"/>
+       <arg name="surface" type="object" interface="wl_surface"/>
+     </request>
+ 
+     <request name="pong">
+       <description summary="respond to a ping event">
+ 	A client must respond to a ping event with a pong request or
+-	the client may be deemed unresponsive. See xdg_shell.ping.
++	the client may be deemed unresponsive. See xdg_wm_base.ping.
+       </description>
+       <arg name="serial" type="uint" summary="serial of the ping event"/>
+     </request>
+@@ -98,7 +101,7 @@
+       <description summary="check if the client is alive">
+ 	The ping event asks the client if it's still alive. Pass the
+ 	serial specified in the event back to the compositor by sending
+-	a "pong" request back with the specified serial. See xdg_shell.ping.
++	a "pong" request back with the specified serial. See xdg_wm_base.pong.
+ 
+ 	Compositors can use this to determine if the client is still
+ 	alive. It's unspecified what will happen if the client doesn't
+@@ -106,13 +109,13 @@
+ 	try to respond in a reasonable amount of time.
+ 
+ 	A compositor is free to ping in any way it wants, but a client must
+-	always respond to any xdg_shell object it created.
++	always respond to any xdg_wm_base object it created.
+       </description>
+       <arg name="serial" type="uint" summary="pass this to the pong request"/>
+     </event>
+   </interface>
+ 
+-  <interface name="zxdg_positioner_v6" version="1">
++  <interface name="xdg_positioner" version="2">
+     <description summary="child surface positioner">
+       The xdg_positioner provides a collection of rules for the placement of a
+       child surface relative to a parent surface. Rules can be defined to ensure
+@@ -162,13 +165,13 @@
+ 	Specify the anchor rectangle within the parent surface that the child
+ 	surface will be placed relative to. The rectangle is relative to the
+ 	window geometry as defined by xdg_surface.set_window_geometry of the
+-	parent surface. The rectangle must be at least 1x1 large.
++	parent surface.
+ 
+ 	When the xdg_positioner object is used to position a child surface, the
+ 	anchor rectangle may not extend outside the window geometry of the
+ 	positioned child's parent surface.
+ 
+-	If a zero or negative size is set the invalid_input error is raised.
++	If a negative size is set the invalid_input error is raised.
+       </description>
+       <arg name="x" type="int" summary="x position of anchor rectangle"/>
+       <arg name="y" type="int" summary="y position of anchor rectangle"/>
+@@ -176,63 +179,54 @@
+       <arg name="height" type="int" summary="height of anchor rectangle"/>
+     </request>
+ 
+-    <enum name="anchor" bitfield="true">
+-      <entry name="none" value="0"
+-	     summary="the center of the anchor rectangle"/>
+-      <entry name="top" value="1"
+-	     summary="the top edge of the anchor rectangle"/>
+-      <entry name="bottom" value="2"
+-	     summary="the bottom edge of the anchor rectangle"/>
+-      <entry name="left" value="4"
+-	     summary="the left edge of the anchor rectangle"/>
+-      <entry name="right" value="8"
+-	     summary="the right edge of the anchor rectangle"/>
++    <enum name="anchor">
++      <entry name="none" value="0"/>
++      <entry name="top" value="1"/>
++      <entry name="bottom" value="2"/>
++      <entry name="left" value="3"/>
++      <entry name="right" value="4"/>
++      <entry name="top_left" value="5"/>
++      <entry name="bottom_left" value="6"/>
++      <entry name="top_right" value="7"/>
++      <entry name="bottom_right" value="8"/>
+     </enum>
+ 
+     <request name="set_anchor">
+-      <description summary="set anchor rectangle anchor edges">
+-	Defines a set of edges for the anchor rectangle. These are used to
+-	derive an anchor point that the child surface will be positioned
+-	relative to. If two orthogonal edges are specified (e.g. 'top' and
+-	'left'), then the anchor point will be the intersection of the edges
+-	(e.g. the top left position of the rectangle); otherwise, the derived
+-	anchor point will be centered on the specified edge, or in the center of
+-	the anchor rectangle if no edge is specified.
+-
+-	If two parallel anchor edges are specified (e.g. 'left' and 'right'),
+-	the invalid_input error is raised.
++      <description summary="set anchor rectangle anchor">
++	Defines the anchor point for the anchor rectangle. The specified anchor
++	is used derive an anchor point that the child surface will be
++	positioned relative to. If a corner anchor is set (e.g. 'top_left' or
++	'bottom_right'), the anchor point will be at the specified corner;
++	otherwise, the derived anchor point will be centered on the specified
++	edge, or in the center of the anchor rectangle if no edge is specified.
+       </description>
+       <arg name="anchor" type="uint" enum="anchor"
+-	   summary="bit mask of anchor edges"/>
++	   summary="anchor"/>
+     </request>
+ 
+-    <enum name="gravity" bitfield="true">
+-      <entry name="none" value="0"
+-	     summary="center over the anchor edge"/>
+-      <entry name="top" value="1"
+-	     summary="position above the anchor edge"/>
+-      <entry name="bottom" value="2"
+-	     summary="position below the anchor edge"/>
+-      <entry name="left" value="4"
+-	     summary="position to the left of the anchor edge"/>
+-      <entry name="right" value="8"
+-	     summary="position to the right of the anchor edge"/>
++    <enum name="gravity">
++      <entry name="none" value="0"/>
++      <entry name="top" value="1"/>
++      <entry name="bottom" value="2"/>
++      <entry name="left" value="3"/>
++      <entry name="right" value="4"/>
++      <entry name="top_left" value="5"/>
++      <entry name="bottom_left" value="6"/>
++      <entry name="top_right" value="7"/>
++      <entry name="bottom_right" value="8"/>
+     </enum>
+ 
+     <request name="set_gravity">
+       <description summary="set child surface gravity">
+ 	Defines in what direction a surface should be positioned, relative to
+-	the anchor point of the parent surface. If two orthogonal gravities are
+-	specified (e.g. 'bottom' and 'right'), then the child surface will be
+-	placed in the specified direction; otherwise, the child surface will be
+-	centered over the anchor point on any axis that had no gravity
+-	specified.
+-
+-	If two parallel gravities are specified (e.g. 'left' and 'right'), the
+-	invalid_input error is raised.
++	the anchor point of the parent surface. If a corner gravity is
++	specified (e.g. 'bottom_right' or 'top_left'), then the child surface
++	will be placed towards the specified gravity; otherwise, the child
++	surface will be centered over the anchor point on any axis that had no
++	gravity specified.
+       </description>
+       <arg name="gravity" type="uint" enum="gravity"
+-	   summary="bit mask of gravity directions"/>
++	   summary="gravity direction"/>
+     </request>
+ 
+     <enum name="constraint_adjustment" bitfield="true">
+@@ -252,7 +246,7 @@
+       <entry name="none" value="0">
+ 	<description summary="don't move the child surface when constrained">
+ 	  Don't alter the surface position even if it is constrained on some
+-	  axis, for example partially outside the edge of a monitor.
++	  axis, for example partially outside the edge of an output.
+ 	</description>
+       </entry>
+       <entry name="slide_x" value="1">
+@@ -304,6 +298,10 @@
+ 	  surface is constrained, the gravity is 'bottom' and the anchor is
+ 	  'bottom', change the gravity to 'top' and the anchor to 'top'.
+ 
++	  The adjusted position is calculated given the original anchor
++	  rectangle and offset, but with the new flipped anchor and gravity
++	  values.
++
+ 	  If the adjusted position also ends up being constrained, the resulting
+ 	  position of the flip_y adjustment will be the one before the
+ 	  adjustment.
+@@ -361,7 +359,7 @@
+     </request>
+   </interface>
+ 
+-  <interface name="zxdg_surface_v6" version="1">
++  <interface name="xdg_surface" version="2">
+     <description summary="desktop user interface surface base interface">
+       An interface that may be implemented by a wl_surface, for
+       implementations that provide a desktop-style user interface.
+@@ -388,11 +386,20 @@
+       manipulate a buffer prior to the first xdg_surface.configure call must
+       also be treated as errors.
+ 
+-      For a surface to be mapped by the compositor, the following conditions
+-      must be met: (1) the client has assigned a xdg_surface based role to the
+-      surface, (2) the client has set and committed the xdg_surface state and
+-      the role dependent state to the surface and (3) the client has committed a
+-      buffer to the surface.
++      Mapping an xdg_surface-based role surface is defined as making it
++      possible for the surface to be shown by the compositor. Note that
++      a mapped surface is not guaranteed to be visible once it is mapped.
++
++      For an xdg_surface to be mapped by the compositor, the following
++      conditions must be met:
++      (1) the client has assigned an xdg_surface-based role to the surface
++      (2) the client has set and committed the xdg_surface state and the
++	  role-dependent state to the surface
++      (3) the client has committed a buffer to the surface
++
++      A newly-unmapped surface is considered to have met condition (1) out
++      of the 3 required conditions for mapping a surface if its role surface
++      has not been destroyed.
+     </description>
+ 
+     <enum name="error">
+@@ -416,20 +423,23 @@
+ 	See the documentation of xdg_toplevel for more details about what an
+ 	xdg_toplevel is and how it is used.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_toplevel_v6"/>
++      <arg name="id" type="new_id" interface="xdg_toplevel"/>
+     </request>
+ 
+     <request name="get_popup">
+       <description summary="assign the xdg_popup surface role">
+-	This creates an xdg_popup object for the given xdg_surface and gives the
+-	associated wl_surface the xdg_popup role.
++	This creates an xdg_popup object for the given xdg_surface and gives
++	the associated wl_surface the xdg_popup role.
++
++	If null is passed as a parent, a parent surface must be specified using
++	some other protocol, before committing the initial state.
+ 
+ 	See the documentation of xdg_popup for more details about what an
+ 	xdg_popup is and how it is used.
+       </description>
+-      <arg name="id" type="new_id" interface="zxdg_popup_v6"/>
+-      <arg name="parent" type="object" interface="zxdg_surface_v6"/>
+-      <arg name="positioner" type="object" interface="zxdg_positioner_v6"/>
++      <arg name="id" type="new_id" interface="xdg_popup"/>
++      <arg name="parent" type="object" interface="xdg_surface" allow-null="true"/>
++      <arg name="positioner" type="object" interface="xdg_positioner"/>
+     </request>
+ 
+     <request name="set_window_geometry">
+@@ -442,6 +452,11 @@
+ 	The window geometry is double buffered, and will be applied at the
+ 	time wl_surface.commit of the corresponding wl_surface is called.
+ 
++	When maintaining a position, the compositor should treat the (x, y)
++	coordinate of the window geometry as the top left corner of the window.
++	A client changing the (x, y) window geometry coordinate should in
++	general not alter the position of the window.
++
+ 	Once the window geometry of the surface is set, it is not possible to
+ 	unset it, and it will remain the same until set_window_geometry is
+ 	called again, even if a new subsurface or buffer is attached.
+@@ -513,34 +528,50 @@
+     </event>
+   </interface>
+ 
+-  <interface name="zxdg_toplevel_v6" version="1">
++  <interface name="xdg_toplevel" version="2">
+     <description summary="toplevel surface">
+       This interface defines an xdg_surface role which allows a surface to,
+       among other things, set window-like properties such as maximize,
+       fullscreen, and minimize, set application-specific metadata like title and
+       id, and well as trigger user interactive operations such as interactive
+       resize and move.
++
++      Unmapping an xdg_toplevel means that the surface cannot be shown
++      by the compositor until it is explicitly mapped again.
++      All active operations (e.g., move, resize) are canceled and all
++      attributes (e.g. title, state, stacking, ...) are discarded for
++      an xdg_toplevel surface when it is unmapped.
++
++      Attaching a null buffer to a toplevel unmaps the surface.
+     </description>
+ 
+     <request name="destroy" type="destructor">
+       <description summary="destroy the xdg_toplevel">
+-	Unmap and destroy the window. The window will be effectively
+-	hidden from the user's point of view, and all state like
+-	maximization, fullscreen, and so on, will be lost.
++	This request destroys the role surface and unmaps the surface;
++	see "Unmapping" behavior in interface section for details.
+       </description>
+     </request>
+ 
+     <request name="set_parent">
+       <description summary="set the parent of this surface">
+-	Set the "parent" of this surface. This window should be stacked
+-	above a parent. The parent surface must be mapped as long as this
+-	surface is mapped.
++	Set the "parent" of this surface. This surface should be stacked
++	above the parent surface and all other ancestor surfaces.
+ 
+ 	Parent windows should be set on dialogs, toolboxes, or other
+ 	"auxiliary" surfaces, so that the parent is raised when the dialog
+ 	is raised.
++
++	Setting a null parent for a child window removes any parent-child
++	relationship for the child. Setting a null parent for a window which
++	currently has no parent is a no-op.
++
++	If the parent is unmapped then its children are managed as
++	though the parent of the now-unmapped parent has become the
++	parent of this surface. If no parent exists for the now-unmapped
++	parent then the children are managed as though they have no
++	parent surface.
+       </description>
+-      <arg name="parent" type="object" interface="zxdg_toplevel_v6" allow-null="true"/>
++      <arg name="parent" type="object" interface="xdg_toplevel" allow-null="true"/>
+     </request>
+ 
+     <request name="set_title">
+@@ -573,6 +604,9 @@
+ 	For example, "org.freedesktop.FooViewer" where the .desktop file is
+ 	"org.freedesktop.FooViewer.desktop".
+ 
++	Like other properties, a set_app_id request can be sent after the
++	xdg_toplevel has been mapped to update the property.
++
+ 	See the desktop-entry specification [0] for more details on
+ 	application identifiers and how they relate to well-known D-Bus
+ 	names and .desktop files.
+@@ -693,12 +727,18 @@
+ 	<description summary="the surface is maximized">
+ 	  The surface is maximized. The window geometry specified in the configure
+ 	  event must be obeyed by the client.
++
++	  The client should draw without shadow or other
++	  decoration outside of the window geometry.
+ 	</description>
+       </entry>
+       <entry name="fullscreen" value="2" summary="the surface is fullscreen">
+ 	<description summary="the surface is fullscreen">
+-	  The surface is fullscreen. The window geometry specified in the configure
+-	  event must be obeyed by the client.
++	  The surface is fullscreen. The window geometry specified in the
++	  configure event is a maximum; the client cannot resize beyond it. For
++	  a surface to cover the whole fullscreened area, the geometry
++	  dimensions must be obeyed by the client. For more details, see
++	  xdg_toplevel.set_fullscreen.
+ 	</description>
+       </entry>
+       <entry name="resizing" value="3" summary="the surface is being resized">
+@@ -716,6 +756,30 @@
+ 	  keyboard or pointer focus.
+ 	</description>
+       </entry>
++      <entry name="tiled_left" value="5" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the left edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
++      <entry name="tiled_right" value="6" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the right edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
++      <entry name="tiled_top" value="7" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the top edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
++      <entry name="tiled_bottom" value="8" since="2">
++	<description summary="the surface is tiled">
++	  The window is currently in a tiled layout and the bottom edge is
++	  considered to be adjacent to another part of the tiling grid.
++	</description>
++      </entry>
+     </enum>
+ 
+     <request name="set_max_size">
+@@ -805,12 +869,11 @@
+ 	Maximize the surface.
+ 
+ 	After requesting that the surface should be maximized, the compositor
+-	will respond by emitting a configure event with the "maximized" state
+-	and the required window geometry. The client should then update its
+-	content, drawing it in a maximized state, i.e. without shadow or other
+-	decoration outside of the window geometry. The client must also
+-	acknowledge the configure when committing the new content (see
+-	ack_configure).
++	will respond by emitting a configure event. Whether this configure
++	actually sets the window maximized is subject to compositor policies.
++	The client must then update its content, drawing in the configured
++	state. The client must also acknowledge the configure when committing
++	the new content (see ack_configure).
+ 
+ 	It is up to the compositor to decide how and where to maximize the
+ 	surface, for example which output and what region of the screen should
+@@ -818,6 +881,10 @@
+ 
+ 	If the surface was already maximized, the compositor will still emit
+ 	a configure event with the "maximized" state.
++
++	If the surface is in a fullscreen state, this request has no direct
++	effect. It may alter the state the surface is returned to when
++	unmaximized unless overridden by the compositor.
+       </description>
+     </request>
+ 
+@@ -826,13 +893,13 @@
+ 	Unmaximize the surface.
+ 
+ 	After requesting that the surface should be unmaximized, the compositor
+-	will respond by emitting a configure event without the "maximized"
+-	state. If available, the compositor will include the window geometry
+-	dimensions the window had prior to being maximized in the configure
+-	request. The client must then update its content, drawing it in a
+-	regular state, i.e. potentially with shadow, etc. The client must also
+-	acknowledge the configure when committing the new content (see
+-	ack_configure).
++	will respond by emitting a configure event. Whether this actually
++	un-maximizes the window is subject to compositor policies.
++	If available and applicable, the compositor will include the window
++	geometry dimensions the window had prior to being maximized in the
++	configure event. The client must then update its content, drawing it in
++	the configured state. The client must also acknowledge the configure
++	when committing the new content (see ack_configure).
+ 
+ 	It is up to the compositor to position the surface after it was
+ 	unmaximized; usually the position the surface had before maximizing, if
+@@ -840,24 +907,63 @@
+ 
+ 	If the surface was already not maximized, the compositor will still
+ 	emit a configure event without the "maximized" state.
++
++	If the surface is in a fullscreen state, this request has no direct
++	effect. It may alter the state the surface is returned to when
++	unmaximized unless overridden by the compositor.
+       </description>
+     </request>
+ 
+     <request name="set_fullscreen">
+-      <description summary="set the window as fullscreen on a monitor">
++      <description summary="set the window as fullscreen on an output">
+ 	Make the surface fullscreen.
+ 
+-	You can specify an output that you would prefer to be fullscreen.
+-	If this value is NULL, it's up to the compositor to choose which
+-	display will be used to map this surface.
++	After requesting that the surface should be fullscreened, the
++	compositor will respond by emitting a configure event. Whether the
++	client is actually put into a fullscreen state is subject to compositor
++	policies. The client must also acknowledge the configure when
++	committing the new content (see ack_configure).
++
++	The output passed by the request indicates the client's preference as
++	to which display it should be set fullscreen on. If this value is NULL,
++	it's up to the compositor to choose which display will be used to map
++	this surface.
+ 
+ 	If the surface doesn't cover the whole output, the compositor will
+ 	position the surface in the center of the output and compensate with
+-	black borders filling the rest of the output.
++	with border fill covering the rest of the output. The content of the
++	border fill is undefined, but should be assumed to be in some way that
++	attempts to blend into the surrounding area (e.g. solid black).
++
++	If the fullscreened surface is not opaque, the compositor must make
++	sure that other screen content not part of the same surface tree (made
++	up of subsurfaces, popups or similarly coupled surfaces) are not
++	visible below the fullscreened surface.
+       </description>
+       <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+     </request>
+-    <request name="unset_fullscreen" />
++
++    <request name="unset_fullscreen">
++      <description summary="unset the window as fullscreen">
++	Make the surface no longer fullscreen.
++
++	After requesting that the surface should be unfullscreened, the
++	compositor will respond by emitting a configure event.
++	Whether this actually removes the fullscreen state of the client is
++	subject to compositor policies.
++
++	Making a surface unfullscreen sets states for the surface based on the following:
++	* the state(s) it may have had before becoming fullscreen
++	* any state(s) decided by the compositor
++	* any state(s) requested by the client while the surface was fullscreen
++
++	The compositor may include the previous window geometry dimensions in
++	the configure event, if applicable.
++
++	The client must also acknowledge the configure when committing the new
++	content (see ack_configure).
++      </description>
++    </request>
+ 
+     <request name="set_minimized">
+       <description summary="set the window as minimized">
+@@ -913,7 +1019,7 @@
+     </event>
+   </interface>
+ 
+-  <interface name="zxdg_popup_v6" version="1">
++  <interface name="xdg_popup" version="2">
+     <description summary="short-lived, popup surfaces for menus">
+       A popup surface is a short-lived, temporary surface. It can be used to
+       implement for example menus, popovers, tooltips and other similar user
+@@ -931,9 +1037,6 @@
+       surface of their own is clicked should dismiss the popup using the destroy
+       request.
+ 
+-      The parent surface must have either the xdg_toplevel or xdg_popup surface
+-      role.
+-
+       A newly created xdg_popup will be stacked on top of all previously created
+       xdg_popup surfaces associated with the same xdg_toplevel.
+ 
+diff --git a/vm_tools/sommelier/sommelier-xdg-shell.c b/vm_tools/sommelier/sommelier-xdg-shell.c
+index a5551b25e..0c11b8de9 100644
+--- a/vm_tools/sommelier/sommelier-xdg-shell.c
++++ b/vm_tools/sommelier/sommelier-xdg-shell.c
+@@ -7,37 +7,37 @@
+ #include <assert.h>
+ #include <stdlib.h>
+ 
+-#include "xdg-shell-unstable-v6-client-protocol.h"
+-#include "xdg-shell-unstable-v6-server-protocol.h"
++#include "xdg-shell-client-protocol.h"
++#include "xdg-shell-server-protocol.h"
+ 
+-struct sl_host_xdg_shell {
++struct sl_host_xdg_wm_base {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_shell_v6* proxy;
++  struct xdg_wm_base* proxy;
+ };
+ 
+ struct sl_host_xdg_surface {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_surface_v6* proxy;
++  struct xdg_surface* proxy;
+ };
+ 
+ struct sl_host_xdg_toplevel {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_toplevel_v6* proxy;
++  struct xdg_toplevel* proxy;
+ };
+ 
+ struct sl_host_xdg_popup {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_popup_v6* proxy;
++  struct xdg_popup* proxy;
+ };
+ 
+ struct sl_host_xdg_positioner {
+   struct sl_context* ctx;
+   struct wl_resource* resource;
+-  struct zxdg_positioner_v6* proxy;
++  struct xdg_positioner* proxy;
+ };
+ 
+ static void sl_xdg_positioner_destroy(struct wl_client* client,
+@@ -52,7 +52,7 @@ static void sl_xdg_positioner_set_size(struct wl_client* client,
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+   double scale = host->ctx->scale;
+ 
+-  zxdg_positioner_v6_set_size(host->proxy, width / scale, height / scale);
++  xdg_positioner_set_size(host->proxy, width / scale, height / scale);
+ }
+ 
+ static void sl_xdg_positioner_set_anchor_rect(struct wl_client* client,
+@@ -70,7 +70,7 @@ static void sl_xdg_positioner_set_anchor_rect(struct wl_client* client,
+   x2 = (x + width) / scale;
+   y2 = (y + height) / scale;
+ 
+-  zxdg_positioner_v6_set_anchor_rect(host->proxy, x1, y1, x2 - x1, y2 - y1);
++  xdg_positioner_set_anchor_rect(host->proxy, x1, y1, x2 - x1, y2 - y1);
+ }
+ 
+ static void sl_xdg_positioner_set_anchor(struct wl_client* client,
+@@ -78,7 +78,7 @@ static void sl_xdg_positioner_set_anchor(struct wl_client* client,
+                                          uint32_t anchor) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_set_anchor(host->proxy, anchor);
++  xdg_positioner_set_anchor(host->proxy, anchor);
+ }
+ 
+ static void sl_xdg_positioner_set_gravity(struct wl_client* client,
+@@ -86,7 +86,7 @@ static void sl_xdg_positioner_set_gravity(struct wl_client* client,
+                                           uint32_t gravity) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_set_gravity(host->proxy, gravity);
++  xdg_positioner_set_gravity(host->proxy, gravity);
+ }
+ 
+ static void sl_xdg_positioner_set_constraint_adjustment(
+@@ -95,8 +95,8 @@ static void sl_xdg_positioner_set_constraint_adjustment(
+     uint32_t constraint_adjustment) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_set_constraint_adjustment(host->proxy,
+-                                               constraint_adjustment);
++  xdg_positioner_set_constraint_adjustment(host->proxy,
++                                           constraint_adjustment);
+ }
+ 
+ static void sl_xdg_positioner_set_offset(struct wl_client* client,
+@@ -106,10 +106,10 @@ static void sl_xdg_positioner_set_offset(struct wl_client* client,
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+   double scale = host->ctx->scale;
+ 
+-  zxdg_positioner_v6_set_offset(host->proxy, x / scale, y / scale);
++  xdg_positioner_set_offset(host->proxy, x / scale, y / scale);
+ }
+ 
+-static const struct zxdg_positioner_v6_interface
++static const struct xdg_positioner_interface
+     sl_xdg_positioner_implementation = {
+         sl_xdg_positioner_destroy,
+         sl_xdg_positioner_set_size,
+@@ -122,7 +122,7 @@ static const struct zxdg_positioner_v6_interface
+ static void sl_destroy_host_xdg_positioner(struct wl_resource* resource) {
+   struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_positioner_v6_destroy(host->proxy);
++  xdg_positioner_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+@@ -139,19 +139,19 @@ static void sl_xdg_popup_grab(struct wl_client* client,
+   struct sl_host_xdg_popup* host = wl_resource_get_user_data(resource);
+   struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource);
+ 
+-  zxdg_popup_v6_grab(host->proxy, host_seat->proxy, serial);
++  xdg_popup_grab(host->proxy, host_seat->proxy, serial);
+ }
+ 
+-static const struct zxdg_popup_v6_interface sl_xdg_popup_implementation = {
++static const struct xdg_popup_interface sl_xdg_popup_implementation = {
+     sl_xdg_popup_destroy, sl_xdg_popup_grab};
+ 
+ static void sl_xdg_popup_configure(void* data,
+-                                   struct zxdg_popup_v6* xdg_popup,
++                                   struct xdg_popup* xdg_popup,
+                                    int32_t x,
+                                    int32_t y,
+                                    int32_t width,
+                                    int32_t height) {
+-  struct sl_host_xdg_popup* host = zxdg_popup_v6_get_user_data(xdg_popup);
++  struct sl_host_xdg_popup* host = xdg_popup_get_user_data(xdg_popup);
+   double scale = host->ctx->scale;
+   int32_t x1, y1, x2, y2;
+ 
+@@ -160,23 +160,23 @@ static void sl_xdg_popup_configure(void* data,
+   x2 = (x + width) * scale;
+   y2 = (y + height) * scale;
+ 
+-  zxdg_popup_v6_send_configure(host->resource, x1, y1, x2 - x1, y2 - y1);
++  xdg_popup_send_configure(host->resource, x1, y1, x2 - x1, y2 - y1);
+ }
+ 
+ static void sl_xdg_popup_popup_done(void* data,
+-                                    struct zxdg_popup_v6* xdg_popup) {
+-  struct sl_host_xdg_popup* host = zxdg_popup_v6_get_user_data(xdg_popup);
++                                    struct xdg_popup* xdg_popup) {
++  struct sl_host_xdg_popup* host = xdg_popup_get_user_data(xdg_popup);
+ 
+-  zxdg_popup_v6_send_popup_done(host->resource);
++  xdg_popup_send_popup_done(host->resource);
+ }
+ 
+-static const struct zxdg_popup_v6_listener sl_xdg_popup_listener = {
++static const struct xdg_popup_listener sl_xdg_popup_listener = {
+     sl_xdg_popup_configure, sl_xdg_popup_popup_done};
+ 
+ static void sl_destroy_host_xdg_popup(struct wl_resource* resource) {
+   struct sl_host_xdg_popup* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_popup_v6_destroy(host->proxy);
++  xdg_popup_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+@@ -193,8 +193,8 @@ static void sl_xdg_toplevel_set_parent(struct wl_client* client,
+   struct sl_host_xdg_toplevel* host_parent =
+       parent_resource ? wl_resource_get_user_data(parent_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_set_parent(host->proxy,
+-                              host_parent ? host_parent->proxy : NULL);
++  xdg_toplevel_set_parent(host->proxy,
++                          host_parent ? host_parent->proxy : NULL);
+ }
+ 
+ static void sl_xdg_toplevel_set_title(struct wl_client* client,
+@@ -202,7 +202,7 @@ static void sl_xdg_toplevel_set_title(struct wl_client* client,
+                                       const char* title) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_title(host->proxy, title);
++  xdg_toplevel_set_title(host->proxy, title);
+ }
+ 
+ static void sl_xdg_toplevel_set_app_id(struct wl_client* client,
+@@ -210,7 +210,7 @@ static void sl_xdg_toplevel_set_app_id(struct wl_client* client,
+                                        const char* app_id) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_app_id(host->proxy, app_id);
++  xdg_toplevel_set_app_id(host->proxy, app_id);
+ }
+ 
+ static void sl_xdg_toplevel_show_window_menu(struct wl_client* client,
+@@ -223,7 +223,7 @@ static void sl_xdg_toplevel_show_window_menu(struct wl_client* client,
+   struct sl_host_seat* host_seat =
+       seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_show_window_menu(
++  xdg_toplevel_show_window_menu(
+       host->proxy, host_seat ? host_seat->proxy : NULL, serial, x, y);
+ }
+ 
+@@ -235,8 +235,8 @@ static void sl_xdg_toplevel_move(struct wl_client* client,
+   struct sl_host_seat* host_seat =
+       seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_move(host->proxy, host_seat ? host_seat->proxy : NULL,
+-                        serial);
++  xdg_toplevel_move(host->proxy, host_seat ? host_seat->proxy : NULL,
++                    serial);
+ }
+ 
+ static void sl_xdg_toplevel_resize(struct wl_client* client,
+@@ -248,8 +248,8 @@ static void sl_xdg_toplevel_resize(struct wl_client* client,
+   struct sl_host_seat* host_seat =
+       seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
+ 
+-  zxdg_toplevel_v6_resize(host->proxy, host_seat ? host_seat->proxy : NULL,
+-                          serial, edges);
++  xdg_toplevel_resize(host->proxy, host_seat ? host_seat->proxy : NULL,
++                      serial, edges);
+ }
+ 
+ static void sl_xdg_toplevel_set_max_size(struct wl_client* client,
+@@ -258,7 +258,7 @@ static void sl_xdg_toplevel_set_max_size(struct wl_client* client,
+                                          int32_t height) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_max_size(host->proxy, width, height);
++  xdg_toplevel_set_max_size(host->proxy, width, height);
+ }
+ 
+ static void sl_xdg_toplevel_set_min_size(struct wl_client* client,
+@@ -267,21 +267,21 @@ static void sl_xdg_toplevel_set_min_size(struct wl_client* client,
+                                          int32_t height) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_min_size(host->proxy, width, height);
++  xdg_toplevel_set_min_size(host->proxy, width, height);
+ }
+ 
+ static void sl_xdg_toplevel_set_maximized(struct wl_client* client,
+                                           struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_maximized(host->proxy);
++  xdg_toplevel_set_maximized(host->proxy);
+ }
+ 
+ static void sl_xdg_toplevel_unset_maximized(struct wl_client* client,
+                                             struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_unset_maximized(host->proxy);
++  xdg_toplevel_unset_maximized(host->proxy);
+ }
+ 
+ static void sl_xdg_toplevel_set_fullscreen(
+@@ -292,25 +292,25 @@ static void sl_xdg_toplevel_set_fullscreen(
+   struct sl_host_output* host_output =
+       output_resource ? wl_resource_get_user_data(resource) : NULL;
+ 
+-  zxdg_toplevel_v6_set_fullscreen(host->proxy,
+-                                  host_output ? host_output->proxy : NULL);
++  xdg_toplevel_set_fullscreen(host->proxy,
++                              host_output ? host_output->proxy : NULL);
+ }
+ 
+ static void sl_xdg_toplevel_unset_fullscreen(struct wl_client* client,
+                                              struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_unset_fullscreen(host->proxy);
++  xdg_toplevel_unset_fullscreen(host->proxy);
+ }
+ 
+ static void sl_xdg_toplevel_set_minimized(struct wl_client* client,
+                                           struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_set_minimized(host->proxy);
++  xdg_toplevel_set_minimized(host->proxy);
+ }
+ 
+-static const struct zxdg_toplevel_v6_interface sl_xdg_toplevel_implementation =
++static const struct xdg_toplevel_interface sl_xdg_toplevel_implementation =
+     {sl_xdg_toplevel_destroy,          sl_xdg_toplevel_set_parent,
+      sl_xdg_toplevel_set_title,        sl_xdg_toplevel_set_app_id,
+      sl_xdg_toplevel_show_window_menu, sl_xdg_toplevel_move,
+@@ -320,33 +320,33 @@ static const struct zxdg_toplevel_v6_interface sl_xdg_toplevel_implementation =
+      sl_xdg_toplevel_unset_fullscreen, sl_xdg_toplevel_set_minimized};
+ 
+ static void sl_xdg_toplevel_configure(void* data,
+-                                      struct zxdg_toplevel_v6* xdg_toplevel,
++                                      struct xdg_toplevel* xdg_toplevel,
+                                       int32_t width,
+                                       int32_t height,
+                                       struct wl_array* states) {
+   struct sl_host_xdg_toplevel* host =
+-      zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++      xdg_toplevel_get_user_data(xdg_toplevel);
+   double scale = host->ctx->scale;
+ 
+-  zxdg_toplevel_v6_send_configure(host->resource, width * scale, height * scale,
++  xdg_toplevel_send_configure(host->resource, width * scale, height * scale,
+                                   states);
+ }
+ 
+ static void sl_xdg_toplevel_close(void* data,
+-                                  struct zxdg_toplevel_v6* xdg_toplevel) {
++                                  struct xdg_toplevel* xdg_toplevel) {
+   struct sl_host_xdg_toplevel* host =
+-      zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++      xdg_toplevel_get_user_data(xdg_toplevel);
+ 
+-  zxdg_toplevel_v6_send_close(host->resource);
++  xdg_toplevel_send_close(host->resource);
+ }
+ 
+-static const struct zxdg_toplevel_v6_listener sl_xdg_toplevel_listener = {
++static const struct xdg_toplevel_listener sl_xdg_toplevel_listener = {
+     sl_xdg_toplevel_configure, sl_xdg_toplevel_close};
+ 
+ static void sl_destroy_host_xdg_toplevel(struct wl_resource* resource) {
+   struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_toplevel_v6_destroy(host->proxy);
++  xdg_toplevel_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+@@ -367,14 +367,15 @@ static void sl_xdg_surface_get_toplevel(struct wl_client* client,
+ 
+   host_xdg_toplevel->ctx = host->ctx;
+   host_xdg_toplevel->resource =
+-      wl_resource_create(client, &zxdg_toplevel_v6_interface, 1, id);
++      wl_resource_create(client, &xdg_toplevel_interface,
++                         wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(
+       host_xdg_toplevel->resource, &sl_xdg_toplevel_implementation,
+       host_xdg_toplevel, sl_destroy_host_xdg_toplevel);
+-  host_xdg_toplevel->proxy = zxdg_surface_v6_get_toplevel(host->proxy);
+-  zxdg_toplevel_v6_set_user_data(host_xdg_toplevel->proxy, host_xdg_toplevel);
+-  zxdg_toplevel_v6_add_listener(host_xdg_toplevel->proxy,
+-                                &sl_xdg_toplevel_listener, host_xdg_toplevel);
++  host_xdg_toplevel->proxy = xdg_surface_get_toplevel(host->proxy);
++  xdg_toplevel_set_user_data(host_xdg_toplevel->proxy, host_xdg_toplevel);
++  xdg_toplevel_add_listener(host_xdg_toplevel->proxy,
++                            &sl_xdg_toplevel_listener, host_xdg_toplevel);
+ }
+ 
+ static void sl_xdg_surface_get_popup(struct wl_client* client,
+@@ -394,15 +395,16 @@ static void sl_xdg_surface_get_popup(struct wl_client* client,
+ 
+   host_xdg_popup->ctx = host->ctx;
+   host_xdg_popup->resource =
+-      wl_resource_create(client, &zxdg_popup_v6_interface, 1, id);
++      wl_resource_create(client, &xdg_popup_interface,
++                         wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(host_xdg_popup->resource,
+                                  &sl_xdg_popup_implementation, host_xdg_popup,
+                                  sl_destroy_host_xdg_popup);
+-  host_xdg_popup->proxy = zxdg_surface_v6_get_popup(
++  host_xdg_popup->proxy = xdg_surface_get_popup(
+       host->proxy, host_parent->proxy, host_positioner->proxy);
+-  zxdg_popup_v6_set_user_data(host_xdg_popup->proxy, host_xdg_popup);
+-  zxdg_popup_v6_add_listener(host_xdg_popup->proxy, &sl_xdg_popup_listener,
+-                             host_xdg_popup);
++  xdg_popup_set_user_data(host_xdg_popup->proxy, host_xdg_popup);
++  xdg_popup_add_listener(host_xdg_popup->proxy, &sl_xdg_popup_listener,
++                         host_xdg_popup);
+ }
+ 
+ static void sl_xdg_surface_set_window_geometry(struct wl_client* client,
+@@ -420,7 +422,7 @@ static void sl_xdg_surface_set_window_geometry(struct wl_client* client,
+   x2 = (x + width) / scale;
+   y2 = (y + height) / scale;
+ 
+-  zxdg_surface_v6_set_window_geometry(host->proxy, x1, y1, x2 - x1, y2 - y1);
++  xdg_surface_set_window_geometry(host->proxy, x1, y1, x2 - x1, y2 - y1);
+ }
+ 
+ static void sl_xdg_surface_ack_configure(struct wl_client* client,
+@@ -428,63 +430,64 @@ static void sl_xdg_surface_ack_configure(struct wl_client* client,
+                                          uint32_t serial) {
+   struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_surface_v6_ack_configure(host->proxy, serial);
++  xdg_surface_ack_configure(host->proxy, serial);
+ }
+ 
+-static const struct zxdg_surface_v6_interface sl_xdg_surface_implementation = {
++static const struct xdg_surface_interface sl_xdg_surface_implementation = {
+     sl_xdg_surface_destroy, sl_xdg_surface_get_toplevel,
+     sl_xdg_surface_get_popup, sl_xdg_surface_set_window_geometry,
+     sl_xdg_surface_ack_configure};
+ 
+ static void sl_xdg_surface_configure(void* data,
+-                                     struct zxdg_surface_v6* xdg_surface,
++                                     struct xdg_surface* xdg_surface,
+                                      uint32_t serial) {
+-  struct sl_host_xdg_surface* host = zxdg_surface_v6_get_user_data(xdg_surface);
++  struct sl_host_xdg_surface* host = xdg_surface_get_user_data(xdg_surface);
+ 
+-  zxdg_surface_v6_send_configure(host->resource, serial);
++  xdg_surface_send_configure(host->resource, serial);
+ }
+ 
+-static const struct zxdg_surface_v6_listener sl_xdg_surface_listener = {
++static const struct xdg_surface_listener sl_xdg_surface_listener = {
+     sl_xdg_surface_configure};
+ 
+ static void sl_destroy_host_xdg_surface(struct wl_resource* resource) {
+   struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_surface_v6_destroy(host->proxy);
++  xdg_surface_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+ 
+-static void sl_xdg_shell_destroy(struct wl_client* client,
++static void sl_xdg_wm_base_destroy(struct wl_client* client,
+                                  struct wl_resource* resource) {
+   wl_resource_destroy(resource);
+ }
+ 
+-static void sl_xdg_shell_create_positioner(struct wl_client* client,
++static void sl_xdg_wm_base_create_positioner(struct wl_client* client,
+                                            struct wl_resource* resource,
+                                            uint32_t id) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+   struct sl_host_xdg_positioner* host_xdg_positioner;
+ 
+   host_xdg_positioner = malloc(sizeof(*host_xdg_positioner));
+   assert(host_xdg_positioner);
+ 
+   host_xdg_positioner->ctx = host->ctx;
+-  host_xdg_positioner->resource =
+-      wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id);
++  host_xdg_positioner->resource = wl_resource_create(
++      client, &xdg_positioner_interface,
++      wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(
+       host_xdg_positioner->resource, &sl_xdg_positioner_implementation,
+       host_xdg_positioner, sl_destroy_host_xdg_positioner);
+-  host_xdg_positioner->proxy = zxdg_shell_v6_create_positioner(host->proxy);
+-  zxdg_positioner_v6_set_user_data(host_xdg_positioner->proxy,
+-                                   host_xdg_positioner);
++  host_xdg_positioner->proxy = xdg_wm_base_create_positioner(host->proxy);
++  xdg_positioner_set_user_data(host_xdg_positioner->proxy,
++                               host_xdg_positioner);
+ }
+ 
+-static void sl_xdg_shell_get_xdg_surface(struct wl_client* client,
++static void sl_xdg_wm_base_get_xdg_surface(struct wl_client* client,
+                                          struct wl_resource* resource,
+                                          uint32_t id,
+                                          struct wl_resource* surface_resource) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+   struct sl_host_surface* host_surface =
+       wl_resource_get_user_data(surface_resource);
+   struct sl_host_xdg_surface* host_xdg_surface;
+@@ -493,71 +496,74 @@ static void sl_xdg_shell_get_xdg_surface(struct wl_client* client,
+   assert(host_xdg_surface);
+ 
+   host_xdg_surface->ctx = host->ctx;
+-  host_xdg_surface->resource =
+-      wl_resource_create(client, &zxdg_surface_v6_interface, 1, id);
++  host_xdg_surface->resource = wl_resource_create(
++      client, &xdg_surface_interface,
++      wl_resource_get_version(resource), id);
+   wl_resource_set_implementation(host_xdg_surface->resource,
+                                  &sl_xdg_surface_implementation,
+                                  host_xdg_surface, sl_destroy_host_xdg_surface);
+   host_xdg_surface->proxy =
+-      zxdg_shell_v6_get_xdg_surface(host->proxy, host_surface->proxy);
+-  zxdg_surface_v6_set_user_data(host_xdg_surface->proxy, host_xdg_surface);
+-  zxdg_surface_v6_add_listener(host_xdg_surface->proxy,
+-                               &sl_xdg_surface_listener, host_xdg_surface);
++      xdg_wm_base_get_xdg_surface(host->proxy, host_surface->proxy);
++  xdg_surface_set_user_data(host_xdg_surface->proxy, host_xdg_surface);
++  xdg_surface_add_listener(host_xdg_surface->proxy,
++                           &sl_xdg_surface_listener, host_xdg_surface);
+   host_surface->has_role = 1;
+ }
+ 
+-static void sl_xdg_shell_pong(struct wl_client* client,
++static void sl_xdg_wm_base_pong(struct wl_client* client,
+                               struct wl_resource* resource,
+                               uint32_t serial) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_shell_v6_pong(host->proxy, serial);
++  xdg_wm_base_pong(host->proxy, serial);
+ }
+ 
+-static const struct zxdg_shell_v6_interface sl_xdg_shell_implementation = {
+-    sl_xdg_shell_destroy, sl_xdg_shell_create_positioner,
+-    sl_xdg_shell_get_xdg_surface, sl_xdg_shell_pong};
++static const struct xdg_wm_base_interface sl_xdg_wm_base_implementation = {
++    sl_xdg_wm_base_destroy, sl_xdg_wm_base_create_positioner,
++    sl_xdg_wm_base_get_xdg_surface, sl_xdg_wm_base_pong};
+ 
+-static void sl_xdg_shell_ping(void* data,
+-                              struct zxdg_shell_v6* xdg_shell,
++static void sl_xdg_wm_base_ping(void* data,
++                              struct xdg_wm_base* xdg_wm_base,
+                               uint32_t serial) {
+-  struct sl_host_xdg_shell* host = zxdg_shell_v6_get_user_data(xdg_shell);
++  struct sl_host_xdg_wm_base* host = xdg_wm_base_get_user_data(xdg_wm_base);
+ 
+-  zxdg_shell_v6_send_ping(host->resource, serial);
++  xdg_wm_base_send_ping(host->resource, serial);
+ }
+ 
+-static const struct zxdg_shell_v6_listener sl_xdg_shell_listener = {
+-    sl_xdg_shell_ping};
++static const struct xdg_wm_base_listener sl_xdg_wm_base_listener = {
++    sl_xdg_wm_base_ping};
+ 
+-static void sl_destroy_host_xdg_shell(struct wl_resource* resource) {
+-  struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
++static void sl_destroy_host_xdg_wm_base(struct wl_resource* resource) {
++  struct sl_host_xdg_wm_base* host = wl_resource_get_user_data(resource);
+ 
+-  zxdg_shell_v6_destroy(host->proxy);
++  xdg_wm_base_destroy(host->proxy);
+   wl_resource_set_user_data(resource, NULL);
+   free(host);
+ }
+ 
+-static void sl_bind_host_xdg_shell(struct wl_client* client,
++static void sl_bind_host_xdg_wm_base(struct wl_client* client,
+                                    void* data,
+                                    uint32_t version,
+                                    uint32_t id) {
+   struct sl_context* ctx = (struct sl_context*)data;
+-  struct sl_host_xdg_shell* host;
++  struct sl_host_xdg_wm_base* host;
+ 
+   host = malloc(sizeof(*host));
+   assert(host);
+   host->ctx = ctx;
+-  host->resource = wl_resource_create(client, &zxdg_shell_v6_interface, 1, id);
+-  wl_resource_set_implementation(host->resource, &sl_xdg_shell_implementation,
+-                                 host, sl_destroy_host_xdg_shell);
+-  host->proxy =
+-      wl_registry_bind(wl_display_get_registry(ctx->display),
+-                       ctx->xdg_shell->id, &zxdg_shell_v6_interface, 1);
+-  zxdg_shell_v6_set_user_data(host->proxy, host);
+-  zxdg_shell_v6_add_listener(host->proxy, &sl_xdg_shell_listener, host);
+-}
+-
+-struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx) {
+-  return sl_global_create(ctx, &zxdg_shell_v6_interface, 1, ctx,
+-                          sl_bind_host_xdg_shell);
+-}
+\ No newline at end of file
++  host->resource = wl_resource_create(client, &xdg_wm_base_interface,
++                                      MIN(version, ctx->xdg_wm_base->version), id);
++  wl_resource_set_implementation(host->resource, &sl_xdg_wm_base_implementation,
++                                 host, sl_destroy_host_xdg_wm_base);
++  host->proxy = wl_registry_bind(
++      wl_display_get_registry(ctx->display), ctx->xdg_wm_base->id,
++      &xdg_wm_base_interface, ctx->xdg_wm_base->version);
++  xdg_wm_base_set_user_data(host->proxy, host);
++  xdg_wm_base_add_listener(host->proxy, &sl_xdg_wm_base_listener, host);
++}
++
++struct sl_global* sl_xdg_wm_base_global_create(struct sl_context* ctx) {
++  return sl_global_create(ctx, &xdg_wm_base_interface, 
++                          ctx->xdg_wm_base->version, ctx,
++                          sl_bind_host_xdg_wm_base);
++}
+diff --git a/vm_tools/sommelier/sommelier.c b/vm_tools/sommelier/sommelier.c
+index ff066e1f3..3fbcde473 100644
+--- a/vm_tools/sommelier/sommelier.c
++++ b/vm_tools/sommelier/sommelier.c
+@@ -33,7 +33,7 @@
+ #include "relative-pointer-unstable-v1-client-protocol.h"
+ #include "text-input-unstable-v1-client-protocol.h"
+ #include "viewporter-client-protocol.h"
+-#include "xdg-shell-unstable-v6-client-protocol.h"
++#include "xdg-shell-client-protocol.h"
+ 
+ // Check that required macro definitions exist.
+ #ifndef XWAYLAND_PATH
+@@ -245,14 +245,14 @@ void sl_sync_point_destroy(struct sl_sync_point* sync_point) {
+   free(sync_point);
+ }
+ 
+-static void sl_internal_xdg_shell_ping(void* data,
+-                                       struct zxdg_shell_v6* xdg_shell,
++static void sl_internal_xdg_wm_base_ping(void* data,
++                                       struct xdg_wm_base* xdg_wm_base,
+                                        uint32_t serial) {
+-  zxdg_shell_v6_pong(xdg_shell, serial);
++  xdg_wm_base_pong(xdg_wm_base, serial);
+ }
+ 
+-static const struct zxdg_shell_v6_listener sl_internal_xdg_shell_listener = {
+-    sl_internal_xdg_shell_ping};
++static const struct xdg_wm_base_listener sl_internal_xdg_wm_base_listener = {
++    sl_internal_xdg_wm_base_ping};
+ 
+ static void sl_send_configure_notify(struct sl_window* window) {
+   xcb_configure_notify_event_t event = {
+@@ -415,8 +415,8 @@ int sl_process_pending_configure_acks(struct sl_window* window,
+   }
+ 
+   if (window->xdg_surface) {
+-    zxdg_surface_v6_ack_configure(window->xdg_surface,
+-                                  window->pending_config.serial);
++    xdg_surface_ack_configure(window->xdg_surface,
++                              window->pending_config.serial);
+   }
+   window->pending_config.serial = 0;
+ 
+@@ -427,8 +427,8 @@ int sl_process_pending_configure_acks(struct sl_window* window,
+ }
+ 
+ static void sl_internal_xdg_surface_configure(
+-    void* data, struct zxdg_surface_v6* xdg_surface, uint32_t serial) {
+-  struct sl_window* window = zxdg_surface_v6_get_user_data(xdg_surface);
++    void* data, struct xdg_surface* xdg_surface, uint32_t serial) {
++  struct sl_window* window = xdg_surface_get_user_data(xdg_surface);
+ 
+   window->next_config.serial = serial;
+   if (!window->pending_config.serial) {
+@@ -449,16 +449,16 @@ static void sl_internal_xdg_surface_configure(
+   }
+ }
+ 
+-static const struct zxdg_surface_v6_listener sl_internal_xdg_surface_listener =
++static const struct xdg_surface_listener sl_internal_xdg_surface_listener =
+     {sl_internal_xdg_surface_configure};
+ 
+ static void sl_internal_xdg_toplevel_configure(
+     void* data,
+-    struct zxdg_toplevel_v6* xdg_toplevel,
++    struct xdg_toplevel* xdg_toplevel,
+     int32_t width,
+     int32_t height,
+     struct wl_array* states) {
+-  struct sl_window* window = zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++  struct sl_window* window = xdg_toplevel_get_user_data(xdg_toplevel);
+   int activated = 0;
+   uint32_t* state;
+   int i = 0;
+@@ -488,21 +488,21 @@ static void sl_internal_xdg_toplevel_configure(
+ 
+   window->allow_resize = 1;
+   wl_array_for_each(state, states) {
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN) {
++    if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN) {
+       window->allow_resize = 0;
+       window->next_config.states[i++] =
+           window->ctx->atoms[ATOM_NET_WM_STATE_FULLSCREEN].value;
+     }
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED) {
++    if (*state == XDG_TOPLEVEL_STATE_MAXIMIZED) {
+       window->allow_resize = 0;
+       window->next_config.states[i++] =
+           window->ctx->atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT].value;
+       window->next_config.states[i++] =
+           window->ctx->atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ].value;
+     }
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_ACTIVATED)
++    if (*state == XDG_TOPLEVEL_STATE_ACTIVATED)
+       activated = 1;
+-    if (*state == ZXDG_TOPLEVEL_V6_STATE_RESIZING)
++    if (*state == XDG_TOPLEVEL_STATE_RESIZING)
+       window->allow_resize = 0;
+   }
+ 
+@@ -518,8 +518,8 @@ static void sl_internal_xdg_toplevel_configure(
+ }
+ 
+ static void sl_internal_xdg_toplevel_close(
+-    void* data, struct zxdg_toplevel_v6* xdg_toplevel) {
+-  struct sl_window* window = zxdg_toplevel_v6_get_user_data(xdg_toplevel);
++    void* data, struct xdg_toplevel* xdg_toplevel) {
++  struct sl_window* window = xdg_toplevel_get_user_data(xdg_toplevel);
+   xcb_client_message_event_t event = {
+       .response_type = XCB_CLIENT_MESSAGE,
+       .format = 32,
+@@ -536,21 +536,21 @@ static void sl_internal_xdg_toplevel_close(
+                  XCB_EVENT_MASK_NO_EVENT, (const char*)&event);
+ }
+ 
+-static const struct zxdg_toplevel_v6_listener
++static const struct xdg_toplevel_listener
+     sl_internal_xdg_toplevel_listener = {sl_internal_xdg_toplevel_configure,
+                                          sl_internal_xdg_toplevel_close};
+ 
+ static void sl_internal_xdg_popup_configure(void* data,
+-                                            struct zxdg_popup_v6* xdg_popup,
++                                            struct xdg_popup* xdg_popup,
+                                             int32_t x,
+                                             int32_t y,
+                                             int32_t width,
+                                             int32_t height) {}
+ 
+ static void sl_internal_xdg_popup_done(void* data,
+-                                       struct zxdg_popup_v6* zxdg_popup_v6) {}
++                                       struct xdg_popup* xdg_popup) {}
+ 
+-static const struct zxdg_popup_v6_listener sl_internal_xdg_popup_listener = {
++static const struct xdg_popup_listener sl_internal_xdg_popup_listener = {
+     sl_internal_xdg_popup_configure, sl_internal_xdg_popup_done};
+ 
+ static void sl_window_set_wm_state(struct sl_window* window, int state) {
+@@ -590,15 +590,15 @@ void sl_window_update(struct sl_window* window) {
+       window->aura_surface = NULL;
+     }
+     if (window->xdg_toplevel) {
+-      zxdg_toplevel_v6_destroy(window->xdg_toplevel);
++      xdg_toplevel_destroy(window->xdg_toplevel);
+       window->xdg_toplevel = NULL;
+     }
+     if (window->xdg_popup) {
+-      zxdg_popup_v6_destroy(window->xdg_popup);
++      xdg_popup_destroy(window->xdg_popup);
+       window->xdg_popup = NULL;
+     }
+     if (window->xdg_surface) {
+-      zxdg_surface_v6_destroy(window->xdg_surface);
++      xdg_surface_destroy(window->xdg_surface);
+       window->xdg_surface = NULL;
+     }
+     window->realized = 0;
+@@ -609,8 +609,8 @@ void sl_window_update(struct sl_window* window) {
+   assert(host_surface);
+   assert(!host_surface->has_role);
+ 
+-  assert(ctx->xdg_shell);
+-  assert(ctx->xdg_shell->internal);
++  assert(ctx->xdg_wm_base);
++  assert(ctx->xdg_wm_base->internal);
+ 
+   if (window->managed) {
+     if (window->transient_for != XCB_WINDOW_NONE) {
+@@ -672,11 +672,11 @@ void sl_window_update(struct sl_window* window) {
+   }
+ 
+   if (!window->xdg_surface) {
+-    window->xdg_surface = zxdg_shell_v6_get_xdg_surface(
+-        ctx->xdg_shell->internal, host_surface->proxy);
+-    zxdg_surface_v6_set_user_data(window->xdg_surface, window);
+-    zxdg_surface_v6_add_listener(window->xdg_surface,
+-                                 &sl_internal_xdg_surface_listener, window);
++    window->xdg_surface = xdg_wm_base_get_xdg_surface(
++        ctx->xdg_wm_base->internal, host_surface->proxy);
++    xdg_surface_set_user_data(window->xdg_surface, window);
++    xdg_surface_add_listener(window->xdg_surface,
++                             &sl_internal_xdg_surface_listener, window);
+   }
+ 
+   if (ctx->aura_shell) {
+@@ -730,47 +730,47 @@ void sl_window_update(struct sl_window* window) {
+   // window is closed.
+   if (ctx->xwayland || !parent) {
+     if (!window->xdg_toplevel) {
+-      window->xdg_toplevel = zxdg_surface_v6_get_toplevel(window->xdg_surface);
+-      zxdg_toplevel_v6_set_user_data(window->xdg_toplevel, window);
+-      zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
++      window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
++      xdg_toplevel_set_user_data(window->xdg_toplevel, window);
++      xdg_toplevel_add_listener(window->xdg_toplevel,
+                                     &sl_internal_xdg_toplevel_listener, window);
+     }
+     if (parent)
+-      zxdg_toplevel_v6_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
++      xdg_toplevel_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
+     if (window->name)
+-      zxdg_toplevel_v6_set_title(window->xdg_toplevel, window->name);
++      xdg_toplevel_set_title(window->xdg_toplevel, window->name);
+     if (window->size_flags & P_MIN_SIZE) {
+-      zxdg_toplevel_v6_set_min_size(window->xdg_toplevel,
++      xdg_toplevel_set_min_size(window->xdg_toplevel,
+                                     window->min_width / ctx->scale,
+                                     window->min_height / ctx->scale);
+     }
+     if (window->size_flags & P_MAX_SIZE) {
+-      zxdg_toplevel_v6_set_max_size(window->xdg_toplevel,
++      xdg_toplevel_set_max_size(window->xdg_toplevel,
+                                     window->max_width / ctx->scale,
+                                     window->max_height / ctx->scale);
+     }
+   } else if (!window->xdg_popup) {
+-    struct zxdg_positioner_v6* positioner;
++    struct xdg_positioner* positioner;
+ 
+-    positioner = zxdg_shell_v6_create_positioner(ctx->xdg_shell->internal);
++    positioner = xdg_wm_base_create_positioner(ctx->xdg_wm_base->internal);
+     assert(positioner);
+-    zxdg_positioner_v6_set_anchor(
++    xdg_positioner_set_anchor(
+         positioner,
+-        ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+-    zxdg_positioner_v6_set_gravity(
++        XDG_POSITIONER_ANCHOR_TOP | XDG_POSITIONER_ANCHOR_LEFT);
++    xdg_positioner_set_gravity(
+         positioner,
+-        ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+-    zxdg_positioner_v6_set_anchor_rect(
++        XDG_POSITIONER_GRAVITY_BOTTOM | XDG_POSITIONER_GRAVITY_RIGHT);
++    xdg_positioner_set_anchor_rect(
+         positioner, (window->x - parent->x) / ctx->scale,
+         (window->y - parent->y) / ctx->scale, 1, 1);
+ 
+-    window->xdg_popup = zxdg_surface_v6_get_popup(
++    window->xdg_popup = xdg_surface_get_popup(
+         window->xdg_surface, parent->xdg_surface, positioner);
+-    zxdg_popup_v6_set_user_data(window->xdg_popup, window);
+-    zxdg_popup_v6_add_listener(window->xdg_popup,
++    xdg_popup_set_user_data(window->xdg_popup, window);
++    xdg_popup_add_listener(window->xdg_popup,
+                                &sl_internal_xdg_popup_listener, window);
+ 
+-    zxdg_positioner_v6_destroy(positioner);
++    xdg_positioner_destroy(positioner);
+   }
+ 
+   if ((window->size_flags & (US_POSITION | P_POSITION)) && parent &&
+@@ -1122,22 +1122,23 @@ static void sl_registry_handler(void* data,
+       data_device_manager->host_global =
+           sl_data_device_manager_global_create(ctx);
+     }
+-  } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
+-    struct sl_xdg_shell* xdg_shell = malloc(sizeof(struct sl_xdg_shell));
+-    assert(xdg_shell);
+-    xdg_shell->ctx = ctx;
+-    xdg_shell->id = id;
+-    xdg_shell->internal = NULL;
+-    xdg_shell->host_global = NULL;
+-    assert(!ctx->xdg_shell);
+-    ctx->xdg_shell = xdg_shell;
++  } else if (strcmp(interface, "xdg_wm_base") == 0) {
++    struct sl_xdg_wm_base* xdg_wm_base = malloc(sizeof(struct sl_xdg_wm_base));
++    assert(xdg_wm_base);
++    xdg_wm_base->ctx = ctx;
++    xdg_wm_base->id = id;
++    xdg_wm_base->version = MIN(2, version);
++    xdg_wm_base->internal = NULL;
++    xdg_wm_base->host_global = NULL;
++    assert(!ctx->xdg_wm_base);
++    ctx->xdg_wm_base = xdg_wm_base;
+     if (ctx->xwayland) {
+-      xdg_shell->internal =
+-          wl_registry_bind(registry, id, &zxdg_shell_v6_interface, 1);
+-      zxdg_shell_v6_add_listener(xdg_shell->internal,
+-                                 &sl_internal_xdg_shell_listener, NULL);
++      xdg_wm_base->internal =
++          wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
++      xdg_wm_base_add_listener(xdg_wm_base->internal,
++                                 &sl_internal_xdg_wm_base_listener, NULL);
+     } else {
+-      xdg_shell->host_global = sl_xdg_shell_global_create(ctx);
++      xdg_wm_base->host_global = sl_xdg_wm_base_global_create(ctx);
+     }
+   } else if (strcmp(interface, "zaura_shell") == 0) {
+     if (version >= MIN_AURA_SHELL_VERSION) {
+@@ -1244,13 +1245,13 @@ static void sl_registry_remover(void* data,
+     ctx->data_device_manager = NULL;
+     return;
+   }
+-  if (ctx->xdg_shell && ctx->xdg_shell->id == id) {
+-    if (ctx->xdg_shell->host_global)
+-      sl_global_destroy(ctx->xdg_shell->host_global);
+-    if (ctx->xdg_shell->internal)
+-      zxdg_shell_v6_destroy(ctx->xdg_shell->internal);
+-    free(ctx->xdg_shell);
+-    ctx->xdg_shell = NULL;
++  if (ctx->xdg_wm_base && ctx->xdg_wm_base->id == id) {
++    if (ctx->xdg_wm_base->host_global)
++      sl_global_destroy(ctx->xdg_wm_base->host_global);
++    if (ctx->xdg_wm_base->internal)
++      xdg_wm_base_destroy(ctx->xdg_wm_base->internal);
++    free(ctx->xdg_wm_base);
++    ctx->xdg_wm_base = NULL;
+     return;
+   }
+   if (ctx->aura_shell && ctx->aura_shell->id == id) {
+@@ -1405,11 +1406,11 @@ static void sl_destroy_window(struct sl_window* window) {
+   }
+ 
+   if (window->xdg_popup)
+-    zxdg_popup_v6_destroy(window->xdg_popup);
++    xdg_popup_destroy(window->xdg_popup);
+   if (window->xdg_toplevel)
+-    zxdg_toplevel_v6_destroy(window->xdg_toplevel);
++    xdg_toplevel_destroy(window->xdg_toplevel);
+   if (window->xdg_surface)
+-    zxdg_surface_v6_destroy(window->xdg_surface);
++    xdg_surface_destroy(window->xdg_surface);
+   if (window->aura_surface)
+     zaura_surface_destroy(window->aura_surface);
+ 
+@@ -1827,15 +1828,15 @@ static void sl_handle_configure_request(struct sl_context* ctx,
+   // that matching contents will arrive.
+   if (window->xdg_toplevel) {
+     if (window->pending_config.serial) {
+-      zxdg_surface_v6_ack_configure(window->xdg_surface,
+-                                    window->pending_config.serial);
++      xdg_surface_ack_configure(window->xdg_surface,
++                                window->pending_config.serial);
+       window->pending_config.serial = 0;
+       window->pending_config.mask = 0;
+       window->pending_config.states_length = 0;
+     }
+     if (window->next_config.serial) {
+-      zxdg_surface_v6_ack_configure(window->xdg_surface,
+-                                    window->next_config.serial);
++      xdg_surface_ack_configure(window->xdg_surface,
++                                window->next_config.serial);
+       window->next_config.serial = 0;
+       window->next_config.mask = 0;
+       window->next_config.states_length = 0;
+@@ -1956,23 +1957,23 @@ static void sl_handle_configure_notify(struct sl_context* ctx,
+ static uint32_t sl_resize_edge(int net_wm_moveresize_size) {
+   switch (net_wm_moveresize_size) {
+     case NET_WM_MOVERESIZE_SIZE_TOPLEFT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
+     case NET_WM_MOVERESIZE_SIZE_TOP:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
++      return XDG_TOPLEVEL_RESIZE_EDGE_TOP;
+     case NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
+     case NET_WM_MOVERESIZE_SIZE_RIGHT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
+     case NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
+     case NET_WM_MOVERESIZE_SIZE_BOTTOM:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
++      return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
+     case NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
+     case NET_WM_MOVERESIZE_SIZE_LEFT:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
++      return XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
+     default:
+-      return ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE;
++      return XDG_TOPLEVEL_RESIZE_EDGE_NONE;
+   }
+ }
+ 
+@@ -2002,15 +2003,15 @@ static void sl_handle_client_message(struct sl_context* ctx,
+         return;
+ 
+       if (event->data.data32[2] == NET_WM_MOVERESIZE_MOVE) {
+-        zxdg_toplevel_v6_move(window->xdg_toplevel, seat->proxy,
++        xdg_toplevel_move(window->xdg_toplevel, seat->proxy,
+                               seat->seat->last_serial);
+       } else {
+         uint32_t edge = sl_resize_edge(event->data.data32[2]);
+ 
+-        if (edge == ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE)
++        if (edge == XDG_TOPLEVEL_RESIZE_EDGE_NONE)
+           return;
+ 
+-        zxdg_toplevel_v6_resize(window->xdg_toplevel, seat->proxy,
++        xdg_toplevel_resize(window->xdg_toplevel, seat->proxy,
+                                 seat->seat->last_serial, edge);
+       }
+     }
+@@ -2029,24 +2030,24 @@ static void sl_handle_client_message(struct sl_context* ctx,
+ 
+       if (changed[ATOM_NET_WM_STATE_FULLSCREEN]) {
+         if (action == NET_WM_STATE_ADD)
+-          zxdg_toplevel_v6_set_fullscreen(window->xdg_toplevel, NULL);
++          xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
+         else if (action == NET_WM_STATE_REMOVE)
+-          zxdg_toplevel_v6_unset_fullscreen(window->xdg_toplevel);
++          xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
+       }
+ 
+       if (changed[ATOM_NET_WM_STATE_MAXIMIZED_VERT] &&
+           changed[ATOM_NET_WM_STATE_MAXIMIZED_HORZ]) {
+         if (action == NET_WM_STATE_ADD)
+-          zxdg_toplevel_v6_set_maximized(window->xdg_toplevel);
++          xdg_toplevel_set_maximized(window->xdg_toplevel);
+         else if (action == NET_WM_STATE_REMOVE)
+-          zxdg_toplevel_v6_unset_maximized(window->xdg_toplevel);
++          xdg_toplevel_unset_maximized(window->xdg_toplevel);
+       }
+     }
+   } else if (event->type == ctx->atoms[ATOM_WM_CHANGE_STATE].value &&
+              event->data.data32[0] == WM_STATE_ICONIC) {
+     struct sl_window* window = sl_lookup_window(ctx, event->window);
+     if (window && window->xdg_toplevel) {
+-      zxdg_toplevel_v6_set_minimized(window->xdg_toplevel);
++      xdg_toplevel_set_minimized(window->xdg_toplevel);
+     }
+   }
+ }
+@@ -2059,7 +2060,7 @@ static void sl_handle_focus_in(struct sl_context* ctx,
+     // window was realized.
+     struct sl_window* parent = sl_lookup_window(ctx, window->transient_for);
+     if (parent && parent->xdg_toplevel && window->xdg_toplevel)
+-      zxdg_toplevel_v6_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
++      xdg_toplevel_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
+   }
+ }
+ 
+@@ -2277,9 +2278,9 @@ static void sl_handle_property_notify(struct sl_context* ctx,
+       return;
+ 
+     if (window->name) {
+-      zxdg_toplevel_v6_set_title(window->xdg_toplevel, window->name);
++      xdg_toplevel_set_title(window->xdg_toplevel, window->name);
+     } else {
+-      zxdg_toplevel_v6_set_title(window->xdg_toplevel, "");
++      xdg_toplevel_set_title(window->xdg_toplevel, "");
+     }
+   } else if (event->atom == XCB_ATOM_WM_NORMAL_HINTS) {
+     struct sl_window* window = sl_lookup_window(ctx, event->window);
+@@ -2316,19 +2317,19 @@ static void sl_handle_property_notify(struct sl_context* ctx,
+       return;
+ 
+     if (window->size_flags & P_MIN_SIZE) {
+-      zxdg_toplevel_v6_set_min_size(window->xdg_toplevel,
++      xdg_toplevel_set_min_size(window->xdg_toplevel,
+                                     window->min_width / ctx->scale,
+                                     window->min_height / ctx->scale);
+     } else {
+-      zxdg_toplevel_v6_set_min_size(window->xdg_toplevel, 0, 0);
++      xdg_toplevel_set_min_size(window->xdg_toplevel, 0, 0);
+     }
+ 
+     if (window->size_flags & P_MAX_SIZE) {
+-      zxdg_toplevel_v6_set_max_size(window->xdg_toplevel,
++      xdg_toplevel_set_max_size(window->xdg_toplevel,
+                                     window->max_width / ctx->scale,
+                                     window->max_height / ctx->scale);
+     } else {
+-      zxdg_toplevel_v6_set_max_size(window->xdg_toplevel, 0, 0);
++      xdg_toplevel_set_max_size(window->xdg_toplevel, 0, 0);
+     }
+   } else if (event->atom == ctx->atoms[ATOM_MOTIF_WM_HINTS].value) {
+     struct sl_window* window = sl_lookup_window(ctx, event->window);
+@@ -3377,7 +3378,7 @@ int main(int argc, char** argv) {
+       .shm = NULL,
+       .shell = NULL,
+       .data_device_manager = NULL,
+-      .xdg_shell = NULL,
++      .xdg_wm_base = NULL,
+       .aura_shell = NULL,
+       .viewporter = NULL,
+       .linux_dmabuf = NULL,
+diff --git a/vm_tools/sommelier/sommelier.h b/vm_tools/sommelier/sommelier.h
+index 40feb52c0..16aab1818 100644
+--- a/vm_tools/sommelier/sommelier.h
++++ b/vm_tools/sommelier/sommelier.h
+@@ -31,7 +31,7 @@ struct sl_shell;
+ struct sl_data_device_manager;
+ struct sl_data_offer;
+ struct sl_data_source;
+-struct sl_xdg_shell;
++struct sl_xdg_wm_base;
+ struct sl_subcompositor;
+ struct sl_aura_shell;
+ struct sl_viewporter;
+@@ -96,7 +96,7 @@ struct sl_context {
+   struct sl_shm* shm;
+   struct sl_shell* shell;
+   struct sl_data_device_manager* data_device_manager;
+-  struct sl_xdg_shell* xdg_shell;
++  struct sl_xdg_wm_base* xdg_wm_base;
+   struct sl_aura_shell* aura_shell;
+   struct sl_viewporter* viewporter;
+   struct sl_linux_dmabuf* linux_dmabuf;
+@@ -356,11 +356,12 @@ struct sl_viewporter {
+   struct wp_viewporter* internal;
+ };
+ 
+-struct sl_xdg_shell {
++struct sl_xdg_wm_base {
+   struct sl_context* ctx;
+   uint32_t id;
++  uint32_t version;
+   struct sl_global* host_global;
+-  struct zxdg_shell_v6* internal;
++  struct xdg_wm_base* internal;
+ };
+ 
+ struct sl_aura_shell {
+@@ -458,9 +459,9 @@ struct sl_window {
+   int max_height;
+   struct sl_config next_config;
+   struct sl_config pending_config;
+-  struct zxdg_surface_v6* xdg_surface;
+-  struct zxdg_toplevel_v6* xdg_toplevel;
+-  struct zxdg_popup_v6* xdg_popup;
++  struct xdg_surface* xdg_surface;
++  struct xdg_toplevel* xdg_toplevel;
++  struct xdg_popup* xdg_popup;
+   struct zaura_surface* aura_surface;
+   struct wl_list link;
+ };
+@@ -504,7 +505,7 @@ struct sl_global* sl_data_device_manager_global_create(struct sl_context* ctx);
+ 
+ struct sl_global* sl_viewporter_global_create(struct sl_context* ctx);
+ 
+-struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx);
++struct sl_global* sl_xdg_wm_base_global_create(struct sl_context* ctx);
+ 
+ struct sl_global* sl_gtk_shell_global_create(struct sl_context* ctx);
+ 
+-- 
+2.23.0
+
diff --git a/pkgs/os-specific/linux/chromium-os/sommelier/default.nix b/pkgs/os-specific/linux/chromium-os/sommelier/default.nix
new file mode 100644
index 00000000000..400671d866a
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/sommelier/default.nix
@@ -0,0 +1,34 @@
+{ common-mk, lib
+, mesa, grpc, openssl, libdrm, xlibs, protobuf, wayland, libxkbcommon, vm_protos
+, libbrillo, libchrome, linuxHeaders, c-ares, zlib
+}:
+
+common-mk {
+  platformSubdir = "vm_tools/sommelier";
+
+  platform2Patches = [
+    ./0010-sommelier-don-t-leak-source-absolute-paths.patch
+    ./0011-sommelier-use-stable-xdg-shell-protocol.patch
+  ];
+
+  buildInputs = [
+    mesa grpc openssl libdrm protobuf wayland libxkbcommon vm_protos libbrillo
+    libchrome linuxHeaders c-ares zlib
+  ] ++ (with xlibs; [ pixman libxcb libX11 ]);
+
+  NIX_CFLAGS_COMPILE = [
+    "-Wno-error=sign-compare"
+    "-Wno-error=class-memaccess"
+    "-Wno-error=maybe-uninitialized"
+  ];
+
+  installPhase = ''
+    mkdir -p $out/bin
+    install sommelier wayland_demo x11_demo $out/bin
+  '';
+
+  meta = with lib; {
+    description = "Nested Wayland compositor with support for X11 forwarding";
+    maintainers = with maintainers; [ qyliss ];
+  };
+}
diff --git a/pkgs/os-specific/linux/chromium-os/update.py b/pkgs/os-specific/linux/chromium-os/update.py
new file mode 100755
index 00000000000..136321e078e
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/update.py
@@ -0,0 +1,117 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -p python3 -i python
+
+import base64
+import csv
+import json
+import subprocess
+import xml.etree.ElementTree as ElementTree
+from codecs import iterdecode
+from operator import itemgetter
+from os import scandir
+from os.path import dirname, splitext
+from re import MULTILINE, fullmatch, match, search
+from urllib.request import urlopen
+
+# ChromiumOS components used in Nixpkgs
+components = [
+    'aosp/platform/external/libchrome',
+    'aosp/platform/external/modp_b64',
+    'chromiumos/overlays/chromiumos-overlay',
+    'chromiumos/platform/crosvm',
+    'chromiumos/platform2',
+    'chromiumos/third_party/adhd',
+    'chromiumos/third_party/kernel',
+    'chromiumos/third_party/modemmanager-next',
+]
+
+git_root = 'https://chromium.googlesource.com/'
+manifest_versions = f'{git_root}chromiumos/manifest-versions'
+buildspecs_url = f'{manifest_versions}/+/refs/heads/master/paladin/buildspecs/'
+
+# CrOS version numbers look like this:
+# [<chrome-major-version>.]<tip-build>.<branch-build>.<branch-branch-build>
+#
+# As far as I can tell, branches are where internal Google
+# modifications are added to turn Chromium OS into Chrome OS, and
+# branch branches are used for fixes for specific devices.  So for
+# Chromium OS they will always be 0.  This is a best guess, and is not
+# documented.
+with urlopen('https://cros-omahaproxy.appspot.com/all') as resp:
+    versions = csv.DictReader(iterdecode(resp, 'utf-8'))
+    stables = filter(lambda v: v['track'] == 'stable-channel', versions)
+    stable = sorted(stables, key=itemgetter('chrome_version'), reverse=True)[0]
+
+chrome_major_version = match(r'\d+', stable['chrome_version'])[0]
+chromeos_tip_build = match(r'\d+', stable['chromeos_version'])[0]
+
+# Find the most recent buildspec for the stable Chrome version and
+# Chromium OS build number.  Its branch build and branch branch build
+# numbers will (almost?) certainly be 0.  It will then end with an rc
+# number -- presumably these are release candidates, one of which
+# becomes the final release.  Presumably the one with the highest rc
+# number.
+with urlopen(f'{buildspecs_url}{chrome_major_version}/?format=TEXT') as resp:
+    listing = base64.decodebytes(resp.read()).decode('utf-8')
+    buildspecs = [(line.split('\t', 1)[1]) for line in listing.splitlines()]
+    buildspecs = [s for s in buildspecs if s.startswith(chromeos_tip_build)]
+    buildspecs.sort(reverse=True)
+    buildspec = splitext(buildspecs[0])[0]
+
+revisions = {}
+
+# Read the buildspec, and extract the git revisions for each component.
+with urlopen(f'{buildspecs_url}{chrome_major_version}/{buildspec}.xml?format=TEXT') as resp:
+    xml = base64.decodebytes(resp.read()).decode('utf-8')
+    root = ElementTree.fromstring(xml)
+    for project in root.findall('project'):
+        revisions[project.get('name')] = project.get('revision')
+
+# Initialize the data that will be output from this script.  Leave the
+# rc number in buildspec so nobody else is subject to the same level
+# of confusion I have been.
+data = {'version': f'{chrome_major_version}.{buildspec}', 'components': {}}
+
+paths = {}
+
+# Fill in the 'components' dictionary with the output from
+# nix-prefetch-git, which can be passed straight to fetchGit when
+# imported by Nix.
+for component in components:
+    name = component.split('/')[-1]
+    url = f'{git_root}{component}'
+    rev = revisions[component]
+    tarball = f'{url}/+archive/{rev}.tar.gz'
+    output = subprocess.check_output(['nix-prefetch-url', '--print-path', '--unpack', '--name', name, tarball])
+    (sha256, path) = output.decode('utf-8').splitlines()
+    paths[component] = path
+    data['components'][component] = {
+        'name': name,
+        'url': url,
+        'rev': rev,
+        'sha256': sha256,
+    }
+
+# Get the version number of libchrome.
+chromiumos_overlay = paths['chromiumos/overlays/chromiumos-overlay']
+contents = scandir(f'{chromiumos_overlay}/chromeos-base/libchrome')
+libchrome_version = lambda name: fullmatch(r'libchrome-(\d+)\.ebuild', name)[1]
+ebuilds = [f for f in contents if f.is_file(follow_symlinks=False)]
+versions = [libchrome_version(f.name) for f in ebuilds]
+latest = sorted(versions, key=int)[-1]
+data['components']['aosp/platform/external/libchrome']['version'] = latest
+
+# Get the version number of the kernel.
+kernel = paths['chromiumos/third_party/kernel']
+makefile = open(f'{kernel}/Makefile').read()
+version = search(r'^VERSION = (.+)$', makefile, MULTILINE)[1]
+patchlevel = search(r'^PATCHLEVEL = (.*?)$', makefile, MULTILINE)[1]
+sublevel = search(r'^SUBLEVEL = (.*?)$', makefile, MULTILINE)[1]
+extra = search(r'^EXTRAVERSION =[ \t]*(.*?)$', makefile, MULTILINE)[1]
+full_ver = '.'.join(filter(None, [version, patchlevel, sublevel])) + extra
+data['components']['chromiumos/third_party/kernel']['version'] = full_ver
+
+# Finally, write the output.
+with open(dirname(__file__) + '/upstream-info.json', 'w') as out:
+    json.dump(data, out, indent=2)
+    out.write('\n')
diff --git a/pkgs/os-specific/linux/chromium-os/upstream-info.json b/pkgs/os-specific/linux/chromium-os/upstream-info.json
new file mode 100644
index 00000000000..50520c4881c
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/upstream-info.json
@@ -0,0 +1,55 @@
+{
+  "version": "78.12499.0.0-rc1",
+  "components": {
+    "aosp/platform/external/libchrome": {
+      "name": "libchrome",
+      "url": "https://chromium.googlesource.com/aosp/platform/external/libchrome",
+      "rev": "f4736afd702d3f9ac65a2810a1fc472d964941b7",
+      "sha256": "1wry24ma855rbjnawkjqyjjp4p4rsv6fa8i63mlg3pp5j7bflzip",
+      "version": "462023"
+    },
+    "aosp/platform/external/modp_b64": {
+      "name": "modp_b64",
+      "url": "https://chromium.googlesource.com/aosp/platform/external/modp_b64",
+      "rev": "afc3e28a3de4a627e3afaf73b4c55ed85c992470",
+      "sha256": "0cyvbdvnfcm958dglm0ci36v4np2fskkjxr8kzncgmhxpxdhkmwj"
+    },
+    "chromiumos/overlays/chromiumos-overlay": {
+      "name": "chromiumos-overlay",
+      "url": "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay",
+      "rev": "63153be50fe6cbcd7126f9eed6b5bdda28526dae",
+      "sha256": "0v5b2mfrg8c927m073xhjcmgbn077s1gs36kvc7m23194y5wa75i"
+    },
+    "chromiumos/platform/crosvm": {
+      "name": "crosvm",
+      "url": "https://chromium.googlesource.com/chromiumos/platform/crosvm",
+      "rev": "0b86007d3e1ee400c6201c00b7dea323d661b50f",
+      "sha256": "1i3wf7f5ikly404ail161llghzw07wsalpdfdfpr5bs321yfkpsp"
+    },
+    "chromiumos/platform2": {
+      "name": "platform2",
+      "url": "https://chromium.googlesource.com/chromiumos/platform2",
+      "rev": "1a01bbebf957f4750021c6689eb65b9fc026338b",
+      "sha256": "1fyasgg2azixddnnsgfccnbjkpm2qbzjkvv22f298hv8qxhp32nr"
+    },
+    "chromiumos/third_party/adhd": {
+      "name": "adhd",
+      "url": "https://chromium.googlesource.com/chromiumos/third_party/adhd",
+      "rev": "72bf5919510c200fdd9a44ed223fd3a871908b49",
+      "sha256": "0fva5pfa8907qczf2lrinwbw60vvwfc9jv536p2lv86pb36q2vly"
+    },
+    "chromiumos/third_party/kernel": {
+      "name": "kernel",
+      "url": "https://chromium.googlesource.com/chromiumos/third_party/kernel",
+      "rev": "673c07c063fb4fc7d50078ba337e5acd7efca18c",
+      "sha256": "01qww3db1r5aw2r75xfv11qa8ysvwhcdw5sfmdwx1cc3l8j45m7g",
+      "version": "4.19.66"
+    },
+    "chromiumos/third_party/modemmanager-next": {
+      "name": "modemmanager-next",
+      "url": "https://chromium.googlesource.com/chromiumos/third_party/modemmanager-next",
+      "rev": "5b752047977b69618f1b31bd08fd38de6f4f5ba3",
+      "sha256": "0369khzax3r3nxf7jx7d2ryv14xi5s5dz60f4ml4cxidcca20xcj"
+    }
+  }
+}
diff --git a/pkgs/os-specific/linux/chromium-os/vm_protos/default.nix b/pkgs/os-specific/linux/chromium-os/vm_protos/default.nix
new file mode 100644
index 00000000000..5f40c5b416b
--- /dev/null
+++ b/pkgs/os-specific/linux/chromium-os/vm_protos/default.nix
@@ -0,0 +1,31 @@
+{ common-mk, lib, go-protobuf, grpc, openssl, protobuf }:
+
+common-mk {
+  pname = "vm_protos";
+  platformSubdir = "vm_tools/proto";
+
+  nativeBuildInputs = [ go-protobuf ];
+  buildInputs = [ grpc openssl protobuf ];
+
+  postPatch = ''
+    substituteInPlace common-mk/proto_library.gni \
+        --replace /usr/bin/grpc_cpp_plugin ${grpc}/bin/grpc_cpp_plugin
+  '';
+
+  installPhase = ''
+    mkdir -p $out/lib/pkgconfig
+    install -m 644 ../../vm_tools/proto/vm_protos.pc $out/lib/pkgconfig
+
+    headerPath=include/vm_protos/proto_bindings
+    mkdir -p $out/$headerPath
+    install -m 644 gen/$headerPath/*.h $out/$headerPath
+
+    install -m 644 *.a $out/lib
+  '';
+
+  meta = with lib; {
+    description = "Protobuf definitions for Chromium OS system VMs";
+    maintainers = with maintainers; [ qyliss ];
+    platform = platforms.all;
+  };
+}
diff --git a/pkgs/os-specific/linux/kernel-headers/default.nix b/pkgs/os-specific/linux/kernel-headers/default.nix
index fb2b9068921..c5895d2f541 100644
--- a/pkgs/os-specific/linux/kernel-headers/default.nix
+++ b/pkgs/os-specific/linux/kernel-headers/default.nix
@@ -3,7 +3,7 @@
 , elf-header
 }:
 
-let
+rec {
   makeLinuxHeaders = { src, version, patches ? [] }: stdenvNoCC.mkDerivation {
     inherit src;
 
@@ -70,8 +70,11 @@ let
       platforms = platforms.linux;
     };
   };
-in {
-  inherit makeLinuxHeaders;
+
+  linuxHeadersPatches = [
+    ./no-relocs.patch # for building x86 kernel headers on non-ELF platforms
+    ./no-dynamic-cc-version-check.patch # so we can use `stdenvNoCC`, see `makeFlags` above
+  ];
 
   linuxHeaders = let version = "4.19.16"; in
     makeLinuxHeaders {
@@ -80,9 +83,6 @@ in {
         url = "mirror://kernel/linux/kernel/v4.x/linux-${version}.tar.xz";
         sha256 = "1pqvn6dsh0xhdpawz4ag27vkw1abvb6sn3869i4fbrz33ww8i86q";
       };
-      patches = [
-         ./no-relocs.patch # for building x86 kernel headers on non-ELF platforms
-         ./no-dynamic-cc-version-check.patch # so we can use `stdenvNoCC`, see `makeFlags` above
-      ];
+      patches = linuxHeadersPatches;
     };
 }
diff --git a/pkgs/os-specific/linux/kernel/linux-cros.nix b/pkgs/os-specific/linux/kernel/linux-cros.nix
new file mode 100644
index 00000000000..626b0bbe6a9
--- /dev/null
+++ b/pkgs/os-specific/linux/kernel/linux-cros.nix
@@ -0,0 +1,34 @@
+{ stdenv, lib, buildPackages, fetchFromGitiles, upstreamInfo, perl, buildLinux
+, modDirVersionArg ? null
+, ... } @ args:
+
+let
+  versionData = upstreamInfo.components."chromiumos/third_party/kernel";
+in
+
+with lib;
+with import ../../../../lib/kernel.nix { inherit lib version; };
+
+buildLinux (args // rec {
+  inherit (versionData) version;
+
+  # modDirVersion needs to be x.y.z, will automatically add .0 if needed
+  modDirVersion =
+    if modDirVersionArg == null
+    then concatStringsSep "." (take 3 (splitVersion "${version}.0"))
+    else modDirVersionArg;
+
+  # branchVersion needs to be x.y
+  extraMeta.branch = versions.majorMinor version;
+
+  src = fetchFromGitiles { inherit (versionData) name url rev sha256; };
+
+  updateScript = ../chromium-os/update.py;
+
+  structuredExtraConfig = {
+    # Enabling this (the default) caused a build failure.  If you can
+    # archieve a successful build with this enabled, go ahead and
+    # enable it.
+    TCG_CR50_SPI = no;
+  } // (args.structuredExtraConfig or {});
+} // (args.argsOverride or {}))
diff --git a/pkgs/os-specific/linux/s6-linux-init/default.nix b/pkgs/os-specific/linux/s6-linux-init/default.nix
new file mode 100644
index 00000000000..f5c77a653b9
--- /dev/null
+++ b/pkgs/os-specific/linux/s6-linux-init/default.nix
@@ -0,0 +1,31 @@
+{ lib, skawarePackages }:
+
+with skawarePackages;
+
+buildPackage {
+  pname = "s6-linux-init";
+  version = "1.0.3.1";
+  sha256 = "1yq2xnp41a1lqpjzvq5jawgy64jwaxalvjdnlvgdpi9bkicgasi1";
+
+  description = "Automated /sbin/init creation for s6-based Linux systems";
+  platforms = lib.platforms.linux;
+
+  outputs = [ "bin" "dev" "doc" "out" ];
+
+  configureFlags = [
+    "--includedir=\${dev}/include"
+    "--with-sysdeps=${skalibs.lib}/lib/skalibs/sysdeps"
+    "--with-include=${skalibs.dev}/include"
+    "--with-include=${s6.dev}/include"
+    "--with-include=${execline.dev}/include"
+    "--with-lib=${skalibs.lib}/lib"
+    "--with-dynlib=${skalibs.lib}/lib"
+    "--with-lib=${s6}/lib"
+  ];
+
+  postInstall = ''
+    find . -type f -executable -delete
+    rm lib*.a.*
+    mv doc $doc/share/doc/s6-linux-init/html
+  '';
+}
diff --git a/pkgs/tools/system/minijail/default.nix b/pkgs/tools/system/minijail/default.nix
index 74f0a84716a..afd8d959d59 100644
--- a/pkgs/tools/system/minijail/default.nix
+++ b/pkgs/tools/system/minijail/default.nix
@@ -1,14 +1,13 @@
 { stdenv, fetchgit, libcap }:
 
 stdenv.mkDerivation rec {
-  shortname = "minijail";
-  name = "${shortname}-${version}";
-  version = "android-9.0.0_r3";
+  pname = "minijail";
+  version = "android-10.0.0_r9";
 
   src = fetchgit {
     url = "https://android.googlesource.com/platform/external/minijail";
     rev = version;
-    sha256 = "1g1g52s3q61amcnx8cv1332sbixpck1bmjzgsrjiw5ix7chrzkp2";
+    sha256 = "0gcfsyim1krrddcklydqfxl8mamaxgail2xl5qp9yclq60km8f22";
   };
 
   buildInputs = [ libcap ];
@@ -20,13 +19,20 @@ stdenv.mkDerivation rec {
     sed -i '/#include <asm\/siginfo.h>/ d' signal_handler.c
   '';
 
+  postPatch = ''
+    patchShebangs platform2_preinstall.sh
+  '';
+
+  postBuild = ''
+    ./platform2_preinstall.sh ${version} $out/include/chromeos
+  '';
+
   installPhase = ''
-    mkdir -p $out/lib
+    mkdir -p $out/lib/pkgconfig $out/include/chromeos $out/bin
     cp -v *.so $out/lib
-    mkdir -p $out/include
-    cp -v libminijail.h $out/include
-    mkdir -p $out/bin
-    cp minijail0 $out/bin
+    cp -v *.pc $out/lib/pkgconfig
+    cp -v libminijail.h scoped_minijail.h $out/include/chromeos
+    cp -v minijail0 $out/bin
   '';
 
   meta = {
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index d6a72d931ec..379cb90f742 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -360,6 +360,8 @@ in
 
   fetchFromGitLab = callPackage ../build-support/fetchgitlab {};
 
+  fetchFromGitiles = callPackage ../build-support/fetchgitiles {};
+
   fetchFromRepoOrCz = callPackage ../build-support/fetchrepoorcz {};
 
   fetchNuGet = callPackage ../build-support/fetchnuget { };
@@ -6140,6 +6142,8 @@ in
 
   s6-dns = skawarePackages.s6-dns;
 
+  s6-linux-init = skawarePackages.s6-linux-init;
+
   s6-linux-utils = skawarePackages.s6-linux-utils;
 
   s6-networking = skawarePackages.s6-networking;
@@ -10906,6 +10910,11 @@ in
 
   chromaprint = callPackage ../development/libraries/chromaprint { };
 
+  chromiumOSPackages = recurseIntoAttrs
+    (callPackage ../os-specific/linux/chromium-os { });
+
+  inherit (chromiumOSPackages) crosvm sommelier;
+
   cl = callPackage ../development/libraries/cl { };
 
   classads = callPackage ../development/libraries/classads { };
@@ -14012,6 +14021,7 @@ in
 
     s6 = callPackage ../tools/system/s6 { };
     s6-dns = callPackage ../tools/networking/s6-dns { };
+    s6-linux-init = callPackage ../os-specific/linux/s6-linux-init { };
     s6-linux-utils = callPackage ../os-specific/linux/s6-linux-utils { };
     s6-networking = callPackage ../tools/networking/s6-networking { };
     s6-portable-utils = callPackage ../tools/misc/s6-portable-utils { };
@@ -16124,7 +16134,9 @@ in
   lkl = callPackage ../applications/virtualization/lkl { };
 
   inherit (callPackages ../os-specific/linux/kernel-headers { })
-    linuxHeaders;
+    linuxHeaders
+    linuxHeadersPatches
+    makeLinuxHeaders;
 
   kernelPatches = callPackage ../os-specific/linux/kernel/patches.nix { };
 
@@ -16132,6 +16144,8 @@ in
 
   klibcShrunk = lowPrio (callPackage ../os-specific/linux/klibc/shrunk.nix { });
 
+  linux_cros = chromiumOSPackages.linux;
+
   linux_mptcp = linux_mptcp_95;
 
   linux_mptcp_94 = callPackage ../os-specific/linux/kernel/linux-mptcp-94.nix {
@@ -16432,6 +16446,7 @@ in
   linux_latest = linuxPackages_latest.kernel;
 
   # Build the kernel modules for the some of the kernels.
+  linuxPackages_cros = linuxPackagesFor pkgs.linux_cros;
   linuxPackages_mptcp = linuxPackagesFor pkgs.linux_mptcp;
   linuxPackages_rpi1 = linuxPackagesFor pkgs.linux_rpi1;
   linuxPackages_rpi2 = linuxPackagesFor pkgs.linux_rpi2;