Merge "Fix frameworks/native compiling against musl"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1db2867..75caac1 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1236,22 +1236,29 @@
std::string path(title);
path.append(" - ").append(String8(service).c_str());
size_t bytes_written = 0;
- status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
- if (status == OK) {
- dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
- std::chrono::duration<double> elapsed_seconds;
- if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
- service == String16("meminfo")) {
- // Use a longer timeout for meminfo, since 30s is not always enough.
- status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
- } else {
- status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
+ if (PropertiesHelper::IsDryRun()) {
+ dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+ dumpsys.writeDumpFooter(STDOUT_FILENO, service, std::chrono::milliseconds(1));
+ } else {
+ status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
+ if (status == OK) {
+ dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+ std::chrono::duration<double> elapsed_seconds;
+ if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+ service == String16("meminfo")) {
+ // Use a longer timeout for meminfo, since 30s is not always enough.
+ status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+ /* as_proto = */ false, elapsed_seconds,
+ bytes_written);
+ } else {
+ status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+ /* as_proto = */ false, elapsed_seconds,
+ bytes_written);
+ }
+ dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
+ bool dump_complete = (status == OK);
+ dumpsys.stopDumpThread(dump_complete);
}
- dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
- bool dump_complete = (status == OK);
- dumpsys.stopDumpThread(dump_complete);
}
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -1831,8 +1838,10 @@
}
/* Run some operations that require root. */
- ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
- ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+ if (!PropertiesHelper::IsDryRun()) {
+ ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
+ ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+ }
ds.AddDir(RECOVERY_DIR, true);
ds.AddDir(RECOVERY_DATA_DIR, true);
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
new file mode 100644
index 0000000..235990a
--- /dev/null
+++ b/data/etc/Android.bp
@@ -0,0 +1,233 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+prebuilt_defaults {
+ name: "frameworks_native_data_etc_defaults",
+ relative_install_path: "permissions",
+ soc_specific: true,
+}
+
+// Modules use the 'prebuilt.xml' suffix to prevent conflicting
+// overridden paths, so that this Android.bp can exist alongside
+// devices that use PRODUCT_COPY_FILES for these files.
+//
+// This override prevention is also possible using a soong_namespace,
+// but that requires every dependent module (e.g. an APEX that includes
+// one of these files) to also reference this namespace, and so on
+// for all dependent modules. It is simpler to just use new path names.
+
+prebuilt_etc {
+ name: "android.hardware.audio.low_latency.prebuilt.xml",
+ src: "android.hardware.audio.low_latency.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.biometrics.face.prebuilt.xml",
+ src: "android.hardware.biometrics.face.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth_le.prebuilt.xml",
+ src: "android.hardware.bluetooth_le.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth.prebuilt.xml",
+ src: "android.hardware.bluetooth.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.concurrent.prebuilt.xml",
+ src: "android.hardware.camera.concurrent.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.flash-autofocus.prebuilt.xml",
+ src: "android.hardware.camera.flash-autofocus.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.front.prebuilt.xml",
+ src: "android.hardware.camera.front.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.full.prebuilt.xml",
+ src: "android.hardware.camera.full.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.raw.prebuilt.xml",
+ src: "android.hardware.camera.raw.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.ethernet.prebuilt.xml",
+ src: "android.hardware.ethernet.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.faketouch.prebuilt.xml",
+ src: "android.hardware.faketouch.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.location.gps.prebuilt.xml",
+ src: "android.hardware.location.gps.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.reboot_escrow.prebuilt.xml",
+ src: "android.hardware.reboot_escrow.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.ambient_temperature.prebuilt.xml",
+ src: "android.hardware.sensor.ambient_temperature.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.barometer.prebuilt.xml",
+ src: "android.hardware.sensor.barometer.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.gyroscope.prebuilt.xml",
+ src: "android.hardware.sensor.gyroscope.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.hinge_angle.prebuilt.xml",
+ src: "android.hardware.sensor.hinge_angle.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.light.prebuilt.xml",
+ src: "android.hardware.sensor.light.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.proximity.prebuilt.xml",
+ src: "android.hardware.sensor.proximity.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.relative_humidity.prebuilt.xml",
+ src: "android.hardware.sensor.relative_humidity.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.telephony.gsm.prebuilt.xml",
+ src: "android.hardware.telephony.gsm.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.telephony.ims.prebuilt.xml",
+ src: "android.hardware.telephony.ims.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.usb.accessory.prebuilt.xml",
+ src: "android.hardware.usb.accessory.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.usb.host.prebuilt.xml",
+ src: "android.hardware.usb.host.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.vulkan.level-0.prebuilt.xml",
+ src: "android.hardware.vulkan.level-0.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.vulkan.version-1_0_3.prebuilt.xml",
+ src: "android.hardware.vulkan.version-1_0_3.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.wifi.prebuilt.xml",
+ src: "android.hardware.wifi.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.device_id_attestation.prebuilt.xml",
+ src: "android.software.device_id_attestation.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.ipsec_tunnels.prebuilt.xml",
+ src: "android.software.ipsec_tunnels.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.opengles.deqp.level-2021-03-01.prebuilt.xml",
+ src: "android.software.opengles.deqp.level-2021-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.sip.voip.prebuilt.xml",
+ src: "android.software.sip.voip.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.verified_boot.prebuilt.xml",
+ src: "android.software.verified_boot.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.vulkan.deqp.level-2021-03-01.prebuilt.xml",
+ src: "android.software.vulkan.deqp.level-2021-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "aosp_excluded_hardware.prebuilt.xml",
+ src: "aosp_excluded_hardware.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "handheld_core_hardware.prebuilt.xml",
+ src: "handheld_core_hardware.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
diff --git a/data/etc/apex/Android.bp b/data/etc/apex/Android.bp
new file mode 100644
index 0000000..8c4929c
--- /dev/null
+++ b/data/etc/apex/Android.bp
@@ -0,0 +1,34 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+apex_key {
+ name: "com.android.hardware.core_permissions.key",
+ public_key: "com.android.hardware.core_permissions.avbpubkey",
+ private_key: "com.android.hardware.core_permissions.pem",
+}
+
+android_app_certificate {
+ name: "com.android.hardware.core_permissions.certificate",
+ certificate: "com.android.hardware.core_permissions",
+}
+
+apex {
+ name: "com.android.hardware.core_permissions",
+ manifest: "apex_manifest.json",
+ key: "com.android.hardware.core_permissions.key",
+ certificate: ":com.android.hardware.core_permissions.certificate",
+ file_contexts: "file_contexts",
+ updatable: false,
+ // Install the apex in /vendor/apex
+ soc_specific: true,
+ prebuilts: [
+ "handheld_core_hardware.prebuilt.xml",
+ "aosp_excluded_hardware.prebuilt.xml",
+ ],
+}
diff --git a/data/etc/apex/apex_manifest.json b/data/etc/apex/apex_manifest.json
new file mode 100644
index 0000000..5bbf229
--- /dev/null
+++ b/data/etc/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.core_permissions",
+ "version": 1
+}
diff --git a/data/etc/apex/com.android.hardware.core_permissions.avbpubkey b/data/etc/apex/com.android.hardware.core_permissions.avbpubkey
new file mode 100644
index 0000000..b9164fb
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.avbpubkey
Binary files differ
diff --git a/data/etc/apex/com.android.hardware.core_permissions.pem b/data/etc/apex/com.android.hardware.core_permissions.pem
new file mode 100644
index 0000000..7e2826d
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAuJjZgFCp6uX+xgKET1FsXYqEPGfYEWUWJ4VSP+Y5fgth/Om3
+XCRBhKSD4CPyL/E9ohh7eSLRqIzw/idUazgCqk+yYLiVkYZiuY02jcui1/Vze9er
+Nwi0ZSwA+zcvKCEOwZ3PBT6W1kehiQ5PU0IS+78po8LoUrvycmvbXJTHlVt1x2bo
+y2DQmxRjIH9xfACwFwh/JnKyr1O2NGjFbk+z3CYx9l7c0Ew9U/kGL3teSbMEi1le
+2PApAHYUA+kXiwjF07aRUN+zzSdZsI7goQXEsmqGXNy7Fzdp/UDocayBmCdI3a35
+igcPRUryBIf1YdSS+E9DwoXRR7pwzs4ajvVTrzuv7UohTnhPwj95TD0E3Z64r7S7
+AT4jtm9gbkAsKNkKOqioGTEIdmvj2prOA4wOUmVBGwOjGcjsyEPJaa56s0WEXUop
++OD2ZMV3StAIwQ5c/gpFzxWl+qATv3MH9MgwAIjT1TDyXv0R+q9JbFbgTtO748RS
+MZUb1i2odggNQCWRtv8fqJ7c51H7pUpHXCXElXHysFq2oBOY4J1jXr1craxsPn1P
+RcImVwAYTV80jOfmYtWhdJhDavDeD4uinLw+4HeZnFNwZXqCJl0LtLxMDRxoDCr7
+YgT2znh9BM6XXg8jekfkDYb5wyloU1eOZJMxF04pGecDB9n1w/OFBA4v0WECAwEA
+AQKCAgEArjhsRsNaqvzo6L7lWurxCJO73Drx3PD36NLWXsKNjl113LpEOO1q/KI8
+aKXkZMUdM0hB+IEZOSfUJzq9XPge49iV9N0hJJidwpv5WfhQN9xLYx2YVTec8kOG
+pZJeqlQQ1kF3am6484HlfjIIQf8BZaH0zb8df0AtQTp0bTtp5pfMYCbLHW/BUiv6
+pmhBlhQcHZECWCo2ZGzwcSRU+Zi1mthdnTXI17qswv0rjlK0GYCgkFgHwV1ghTPs
+DgjHFIxyES+klJyc2MoDxzQB41dLXkxVhX06Al5lZQUGnIqAQTcKeVZCRrgE/JQQ
+OKCMwglbsIk23XdonnbjEvvIaxY1JHjcnPBpOC4+O11fE0DiHXK3GBj5KlfVvB5D
+oMWko3R/Ky/T/KJhHYXbC1H71oYueCaY57kHFKk2k3qRJG4DU4MY20cfUZ0vp14H
+KJ++gDy0pxxjl4ZUiryBCti5k5GPU8Mm46MLJ/YPdX6Dj1nMtOgGpZkGQYIKPhEI
+qZjZBRyZlHeTJsTMc8Eh3/Krimmra5ID95HfJnTTHHshbRcLwL6/zMTU5fkwarsC
+f4HQ0602/9HqyI8Ty1S9Z4oByjwfW2uDcosnuOPfk/8XwfLWxrf2+TsAd3cXhOKw
+rwUfELzcgYNueLGTJOCsEJfo8NIIEGJCNSgMnWXmIAUIAlrMP8ECggEBAOt9X4Lb
+fkrQLjcQ+K1oOI0Q+43htNRYXiG2IDhmDlA+UnqPP+9j2cVyuo4QYhKTFXRbbezR
+blUHAowd4hKHtODaHMuq90KbeByVNB8idcIb+ELAOK4Ff+qd9ijrBIOuZZQB+KOo
+SlxVjy1LM0QGtUTJRHx4dkCmp+hMqrIc4LQOWd4hV5h85Oj8kp1L1eMvxEStUtwP
+tYR80OoOdDxgXcBHLdPs4rc0WunRabGE+cnCMrTy31D95OWg6aw/+XKSTUS5Hfdy
+4jDIwP8DR6JU71qNgen+fwrHFeDienM40sSpi85/WQndQW5TwOMbDlEfmgn6D4+s
+rVWqFk1XElfwwSkCggEBAMisvdv5fH4UeH+tz5cF5f3ZNY+NX8uj85wCsJAPaAVx
+i3t8BqEKUPA6FPt9SDMWg4QtgSSl0NmhH2F9CcAZUCiTZUrtgqyIo80ALONW1FR9
+ofElvZEeV2IzKn3Ci4HA2pKRtMcjjVLwxzdoHakbPS9CbdCGKYE3W75Huw410IW6
+gV4zQ2mWHT+FxXaatl6Arj0x7DHLeSrMV33uxcYWoclmrAK24uhq2gwhtC8U0SvY
+rtJ7+KpCRd5v3Cyzo2AEbZKyJYVKbMDu9RHDZwkZw6wVqaOKBPJVyC++yidksexX
+ZT0WGX0f23t+2jbbsNY6H27pJm9ApLuAYwiMGv9n/XkCggEADLlAcNyVLUukQ5tq
+JExuScjyHo9kati/dUjW4tU4zsMfR7n3tWKKwK1bQRPHiMNjtF7ASLxkHrn7PEDd
+Fy0367I9Pg/lvjaSPdEd+NSu0icaudiS92wapj2UsE9Kdib1HBMjMQyFwAlrbAIV
+KgbGwomxZpxHn2Shy95glrESvwfLeUIJ7pZI9AG5lkAjtVu+WguXX4aFwzvPOeZA
+B4cZaasu4bV55nYwt1N2R34s1ObmQHqi8EhXlsSj+4eVXchj3mO2J8mQSRx/uQef
+VjkKmbTtoQv8J0PsfbMe9JzMXo3enPCqiernfyONV3f9xQpVE1bsglHNJ8TB4bnj
+pta+SQKCAQEArDqNrFkAftkk3jgXnX9jeC3O6UilugoZj4FDdjCyz1E3LCEzM02+
+T58Z2QoaSDZ/Y5cGaqShjdbaLvp4vtU61chDPD6CU3/mTZBj9i3UiDtXHLeObhlD
+WDWft1WcFB2nufmx1OPvbArYf/Ys1rFZHtF9nGU5A/y2EaZQpY6MS+nZFDcdGWbL
+7XPrGLMJ6Cu63yyUkdwXPyMnyB6AwVU1P7yNzrqWHnFueNEIawwLxfzvdhkOP1on
+yxPoPLlkc4j5XdjlmPNaSXANB1TUfpwNMwlYkdJoEnCLImc16v9iMPyFGBt6fsgz
+wFcMA98jc4lo5vDVmtA5Ue+Lj49nsGLYyQKCAQEAoB21vLDm7sLcZhzHFnh7h3L0
+wLMFMyQ0QDMWOqrlABcME21CWhibu8XwouF+hHLKX9GjaBB3ujkyeun1x8MpGQwT
+1SrMVN4osHpFrCh85uK5mabsqC8YjICIncU1U1ykxDV9v7TXuXgMtUIMKPFcUQLv
+ckf/PNE1Fvt5ESn2GIxk+ibM0L2kzHgDFgwiPx+k8GmJt5VZSXwehPmH6jgyCBIv
+kPHos1Q/z2LtfdUZcGhwX88mBNBpk3UXjiU8qO+ddoXCRgbThFDqYvOcdacbKGc0
+upFMhNsTWocn7CW0rbzusTsTt6bSWCGas8f9G9CMNN6rp8SW7Qc04m6sXVjPbw==
+-----END RSA PRIVATE KEY-----
diff --git a/data/etc/apex/com.android.hardware.core_permissions.pk8 b/data/etc/apex/com.android.hardware.core_permissions.pk8
new file mode 100644
index 0000000..4497844
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.pk8
Binary files differ
diff --git a/data/etc/apex/com.android.hardware.core_permissions.x509.pem b/data/etc/apex/com.android.hardware.core_permissions.x509.pem
new file mode 100644
index 0000000..57a311d
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF7zCCA9cCFD7UZbcK7ZVyJegJvOs8e5T/n0DLMA0GCSqGSIb3DQEBCwUAMIGy
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEuMCwGA1UEAwwlY29t
+LmFuZHJvaWQuaGFyZHdhcmUuY29yZV9wZXJtaXNzaW9uczAgFw0yMTA4MjYyMDM2
+NTBaGA80NzU5MDcyMzIwMzY1MFowgbIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+YWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRy
+b2lkMRAwDgYDVQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFu
+ZHJvaWQuY29tMS4wLAYDVQQDDCVjb20uYW5kcm9pZC5oYXJkd2FyZS5jb3JlX3Bl
+cm1pc3Npb25zMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1ZGPs2s2
+R9/+jd3dHLH0nt4Z5WWduQ4Wqy6H9oojktTCv0IJekfiC6L0VHOvW9DKtSEGWTJg
+sJdoEpd2KDhNxAdjbE6k50AfKD0CAE0MAX2MyJIpUz7b6p6p7kxB7xpJohSGDOSZ
+otuMJ16W99PElwOtQr99Wztf+WehmEkKYDUVA0V3+UP3s0quAo3ZrFYgZxXy51YF
+/rcM+HFNrpBRNZRhm3n/2uM4vqt+HTjUFvPuxFIq44DH64ofD7OYBOTbq7rU3lFr
+jEP4IlVH1mjyirh0pWIzXtqhcj2yfV8HjqnwHz+DhIA7kI1hZNOTotTiYKZszboy
+mvo8YA+fuSDCohFxVJVHZGFu+FA+m353ZPLTDTee+d3F9JGbLxa3NoPAgDIyU/tR
+KD7+fKxfr32coZzf3bDi9T4CHBoHKoikRWqOAhkZ/xGvjX12bI6eS1QP9THGu3d6
+o+ZzSZDPR9GSu8ggFtkRGgaIIbgV3y4XUKqLK3+pyg14tHwqvSYMItZ7oOYKMT47
+R9qb8MlvAWS2ooZlJwSkGSM3y0pTwy3rKXug+Cpvx7zjc3Nm/srzdPAmrEvBTZZN
+k0J1oYKqiNHV1N3PIlMRE2d4g7MVF4GEwrAgL126JZOOmzefkP59eAPNrH6Coyka
+3pAVnifemHYZlhWpbKO6pnuxEwvBGXvJlgkCAwEAATANBgkqhkiG9w0BAQsFAAOC
+AgEAfc6TD6fURc9sKHn5TSi30rIlarR6h1TbxFL4PQroEXWafkNmOMujdyV6YZlZ
+j/lzU4ko+Pn3y1aU4r88PkrjkR2Ttf01H3wj8IkTVyl3kN3o/Ud2jJygL3SbjMS1
+CAxiotvPA3lst3KN3nnyFLe02EB4OIi8fS14/kUVFVz+djpGDhi/lJUzcTCzO1NR
+yoC3RuAHBrly1+0QYcXiRTtvgnXrUqsZery8pysR7OK8fWkJzQ6I6OipElrcRzfK
+qoRq/u7nn9FJxXauVjM5HNCPq1VsB8+/FQqP2CgvxNPtkxy8AkXS3hKMBC0Id0Mo
+sDsAr88QDnCb5DqrWSMDKTKA0k+2a6QwS72ANkK5Uq2Hf/xUVjn+yHLSFuo4pCYe
+TX4ZCjK8My+XPWEiHBV/AELAWA9SxxZFhHmyuPj3MwN5uJcPNPsQepnhpeGv0Dlp
+J7UfzkdAZvOyQ+9CAQfu8+e2MilLHC3uqfnGLpHGkcHoN93rmH1x14JdapKKk3XL
+4Wo0RzEjGQekjMF0topQSqDTukOMdtZ1T0WTVOstYLlNqlhn0ZVbwVANGklN/fDW
+d6OpayLPuuaLBAM6Ivnv7n4XA49ojd9Gw305Ha/ATEoH9KwImFjvUa4d9SkR0haP
+hAiGhpaWViEe2zXOpzLhePgqc2gJ/IO7vIgrVks0iVeBoWE=
+-----END CERTIFICATE-----
diff --git a/data/etc/apex/file_contexts b/data/etc/apex/file_contexts
new file mode 100644
index 0000000..6524a5e
--- /dev/null
+++ b/data/etc/apex/file_contexts
@@ -0,0 +1,2 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 9875079..9bca1f3 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -120,7 +120,6 @@
"ParcelFileDescriptor.cpp",
"PersistableBundle.cpp",
"ProcessState.cpp",
- "RpcAddress.cpp",
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
@@ -263,6 +262,7 @@
],
srcs: [
"RpcTransportTls.cpp",
+ "RpcCertificateUtils.cpp",
],
}
@@ -329,6 +329,7 @@
"libbinder_ndk",
"libutils",
],
+ export_include_dirs: ["include_rpc_unstable"],
// enumerate stable entry points, for apex use
stubs: {
@@ -338,14 +339,15 @@
// This library is intentionally limited to these targets, and it will be removed later.
// Do not expand the visibility.
visibility: [
- "//packages/modules/Virtualization/authfs:__subpackages__",
- "//packages/modules/Virtualization/compos:__subpackages__",
- "//packages/modules/Virtualization/microdroid",
- "//packages/modules/Virtualization/microdroid_manager",
- "//packages/modules/Virtualization/virtualizationservice",
+ "//packages/modules/Virtualization:__subpackages__",
],
}
+filegroup {
+ name: "libbinder_rpc_unstable_header",
+ srcs: ["include_rpc_unstable/binder_rpc_unstable.hpp"],
+}
+
// libbinder historically contained additional interfaces that provided specific
// functionality in the platform but have nothing to do with binder itself. These
// are moved out of libbinder in order to avoid the overhead of their vtables.
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 55566e2..92df874 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -36,7 +36,8 @@
// ---------------------------------------------------------------------------
Mutex BpBinder::sTrackingLock;
-std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap;
+std::unordered_map<int32_t, uint32_t> BpBinder::sTrackingMap;
+std::unordered_map<int32_t, uint32_t> BpBinder::sLastLimitCallbackMap;
int BpBinder::sNumTrackedUids = 0;
std::atomic_bool BpBinder::sCountByUidEnabled(false);
binder_proxy_limit_callback BpBinder::sLimitCallback;
@@ -47,6 +48,10 @@
// Another arbitrary value a binder count needs to drop below before another callback will be called
uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
+// Once the limit has been exceeded, keep calling the limit callback for every this many new proxies
+// created over the limit.
+constexpr uint32_t REPEAT_LIMIT_CALLBACK_INTERVAL = 1000;
+
enum {
LIMIT_REACHED_MASK = 0x80000000, // A flag denoting that the limit has been reached
COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value
@@ -120,12 +125,24 @@
if (sBinderProxyThrottleCreate) {
return nullptr;
}
+ trackedValue = trackedValue & COUNTING_VALUE_MASK;
+ uint32_t lastLimitCallbackAt = sLastLimitCallbackMap[trackedUid];
+
+ if (trackedValue > lastLimitCallbackAt &&
+ (trackedValue - lastLimitCallbackAt > REPEAT_LIMIT_CALLBACK_INTERVAL)) {
+ ALOGE("Still too many binder proxy objects sent to uid %d from uid %d (%d proxies "
+ "held)",
+ getuid(), trackedUid, trackedValue);
+ if (sLimitCallback) sLimitCallback(trackedUid);
+ sLastLimitCallbackMap[trackedUid] = trackedValue;
+ }
} else {
if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
getuid(), trackedUid, trackedValue);
sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
if (sLimitCallback) sLimitCallback(trackedUid);
+ sLastLimitCallbackMap[trackedUid] = trackedValue & COUNTING_VALUE_MASK;
if (sBinderProxyThrottleCreate) {
ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
" count drops below %d",
@@ -139,7 +156,7 @@
return sp<BpBinder>::make(BinderHandle{handle}, trackedUid);
}
-sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, const RpcAddress& address) {
+sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, uint64_t address) {
LOG_ALWAYS_FATAL_IF(session == nullptr, "BpBinder::create null session");
// These are not currently tracked, since there is no UID or other
@@ -176,7 +193,7 @@
return std::holds_alternative<RpcHandle>(mHandle);
}
-const RpcAddress& BpBinder::rpcAddress() const {
+uint64_t BpBinder::rpcAddress() const {
return std::get<RpcHandle>(mHandle).address;
}
@@ -465,8 +482,9 @@
((trackedValue & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark)
)) {
ALOGI("Limit reached bit reset for uid %d (fewer than %d proxies from uid %d held)",
- getuid(), mTrackedUid, sBinderProxyCountLowWatermark);
+ getuid(), sBinderProxyCountLowWatermark, mTrackedUid);
sTrackingMap[mTrackedUid] &= ~LIMIT_REACHED_MASK;
+ sLastLimitCallbackMap.erase(mTrackedUid);
}
if (--sTrackingMap[mTrackedUid] == 0) {
sTrackingMap.erase(mTrackedUid);
@@ -492,7 +510,7 @@
{
ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
if (CC_UNLIKELY(isRpcBinder())) {
- (void)rpcSession()->sendDecStrong(rpcAddress());
+ (void)rpcSession()->sendDecStrong(this);
return;
}
IF_ALOGV() {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index fa9f3a9..9e04ffe 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1426,6 +1426,25 @@
return ret;
}
+#ifndef __ANDROID_VNDK__
+status_t IPCThreadState::getProcessFreezeInfo(pid_t pid, uint32_t *sync_received,
+ uint32_t *async_received)
+{
+ int ret = 0;
+ binder_frozen_status_info info;
+ info.pid = pid;
+
+#if defined(__ANDROID__)
+ if (ioctl(self()->mProcess->mDriverFD, BINDER_GET_FROZEN_INFO, &info) < 0)
+ ret = -errno;
+#endif
+ *sync_received = info.sync_recv;
+ *async_received = info.async_recv;
+
+ return ret;
+}
+#endif
+
status_t IPCThreadState::freeze(pid_t pid, bool enable, uint32_t timeout_ms) {
struct binder_freeze_info info;
int ret = 0;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b545484..9f95167 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -205,11 +205,11 @@
if (binder) {
status_t status = writeInt32(1); // non-null
if (status != OK) return status;
- RpcAddress address = RpcAddress::zero();
+ uint64_t address;
// TODO(b/167966510): need to undo this if the Parcel is not sent
status = mSession->state()->onBinderLeaving(mSession, binder, &address);
if (status != OK) return status;
- status = address.writeToParcel(this);
+ status = writeUint64(address);
if (status != OK) return status;
} else {
status_t status = writeInt32(0); // null
@@ -237,7 +237,7 @@
return INVALID_OPERATION;
}
}
- const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 0;
+ const int32_t handle = proxy ? proxy->getPrivateAccessor().binderHandle() : 0;
obj.hdr.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
@@ -279,15 +279,15 @@
if (isForRpc()) {
LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel");
- int32_t isNull;
- status_t status = readInt32(&isNull);
+ int32_t isPresent;
+ status_t status = readInt32(&isPresent);
if (status != OK) return status;
sp<IBinder> binder;
- if (isNull & 1) {
- auto addr = RpcAddress::zero();
- if (status_t status = addr.readFromParcel(*this); status != OK) return status;
+ if (isPresent & 1) {
+ uint64_t addr;
+ if (status_t status = readUint64(&addr); status != OK) return status;
if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder);
status != OK)
return status;
@@ -572,7 +572,7 @@
LOG_ALWAYS_FATAL_IF(mData != nullptr, "format must be set before data is written");
if (binder && binder->remoteBinder() && binder->remoteBinder()->isRpcBinder()) {
- markForRpc(binder->remoteBinder()->getPrivateAccessorForId().rpcSession());
+ markForRpc(binder->remoteBinder()->getPrivateAccessor().rpcSession());
}
}
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 15b8604..4fe4fe6 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -212,7 +212,7 @@
binder_node_info_for_ref info;
memset(&info, 0, sizeof(binder_node_info_for_ref));
- info.handle = binder->getPrivateAccessorForId().binderHandle();
+ info.handle = binder->getPrivateAccessor().binderHandle();
status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
@@ -301,7 +301,7 @@
return nullptr;
}
- sp<BpBinder> b = BpBinder::create(handle);
+ sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);
e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
deleted file mode 100644
index ffc94b9..0000000
--- a/libs/binder/RpcAddress.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2020 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 <binder/RpcAddress.h>
-
-#include <android-base/hex.h>
-#include <binder/Parcel.h>
-
-#include "Debug.h"
-#include "RpcState.h"
-#include "RpcWireFormat.h"
-
-namespace android {
-
-RpcAddress RpcAddress::zero() {
- return RpcAddress();
-}
-
-bool RpcAddress::isZero() const {
- RpcWireAddress ZERO{.options = 0};
- return memcmp(mRawAddr.get(), &ZERO, sizeof(RpcWireAddress)) == 0;
-}
-
-static void ReadRandomBytes(uint8_t* buf, size_t len) {
- int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
- if (fd == -1) {
- ALOGE("%s: cannot read /dev/urandom", __func__);
- return;
- }
-
- size_t n;
- while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) {
- len -= n;
- buf += n;
- }
- if (len > 0) {
- ALOGW("%s: there are %d bytes skipped", __func__, (int)len);
- }
- close(fd);
-}
-
-RpcAddress RpcAddress::random(bool forServer) {
- // The remainder of this header acts as reserved space for different kinds
- // of binder objects.
- uint64_t options = RPC_WIRE_ADDRESS_OPTION_CREATED;
-
- // servers and clients allocate addresses independently, so this bit can
- // tell you where an address originates
- if (forServer) options |= RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
-
- RpcAddress ret;
- RpcWireAddress* raw = ret.mRawAddr.get();
-
- raw->options = options;
- ReadRandomBytes(raw->address, sizeof(raw->address));
-
- LOG_RPC_DETAIL("Creating new address: %s", ret.toString().c_str());
- return ret;
-}
-
-bool RpcAddress::isForServer() const {
- return mRawAddr.get()->options & RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
-}
-
-bool RpcAddress::isRecognizedType() const {
- uint64_t allKnownOptions = RPC_WIRE_ADDRESS_OPTION_CREATED | RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
- return (mRawAddr.get()->options & ~allKnownOptions) == 0;
-}
-
-RpcAddress RpcAddress::fromRawEmbedded(const RpcWireAddress* raw) {
- RpcAddress addr;
- memcpy(addr.mRawAddr.get(), raw, sizeof(RpcWireAddress));
- return addr;
-}
-
-const RpcWireAddress& RpcAddress::viewRawEmbedded() const {
- return *mRawAddr.get();
-}
-
-bool RpcAddress::operator<(const RpcAddress& rhs) const {
- return std::memcmp(mRawAddr.get(), rhs.mRawAddr.get(), sizeof(RpcWireAddress)) < 0;
-}
-
-std::string RpcAddress::toString() const {
- return base::HexString(mRawAddr.get(), sizeof(RpcWireAddress));
-}
-
-status_t RpcAddress::writeToParcel(Parcel* parcel) const {
- return parcel->write(mRawAddr.get(), sizeof(RpcWireAddress));
-}
-
-status_t RpcAddress::readFromParcel(const Parcel& parcel) {
- return parcel.read(mRawAddr.get(), sizeof(RpcWireAddress));
-}
-
-RpcAddress::~RpcAddress() {}
-RpcAddress::RpcAddress() : mRawAddr(std::make_shared<RpcWireAddress>()) {}
-
-} // namespace android
diff --git a/libs/binder/RpcCertificateUtils.cpp b/libs/binder/RpcCertificateUtils.cpp
new file mode 100644
index 0000000..d91736c
--- /dev/null
+++ b/libs/binder/RpcCertificateUtils.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define LOG_TAG "RpcCertificateUtils"
+#include <log/log.h>
+
+#include <binder/RpcCertificateUtils.h>
+
+#include "Utils.h"
+
+namespace android {
+
+namespace {
+
+bssl::UniquePtr<X509> fromPem(const std::vector<uint8_t>& cert) {
+ if (cert.size() > std::numeric_limits<int>::max()) return nullptr;
+ bssl::UniquePtr<BIO> certBio(BIO_new_mem_buf(cert.data(), static_cast<int>(cert.size())));
+ return bssl::UniquePtr<X509>(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
+}
+
+bssl::UniquePtr<X509> fromDer(const std::vector<uint8_t>& cert) {
+ if (cert.size() > std::numeric_limits<long>::max()) return nullptr;
+ const unsigned char* data = cert.data();
+ auto expectedEnd = data + cert.size();
+ bssl::UniquePtr<X509> ret(d2i_X509(nullptr, &data, static_cast<long>(cert.size())));
+ if (data != expectedEnd) {
+ ALOGE("%s: %td bytes remaining!", __PRETTY_FUNCTION__, expectedEnd - data);
+ return nullptr;
+ }
+ return ret;
+}
+
+} // namespace
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
+ RpcCertificateFormat format) {
+ switch (format) {
+ case RpcCertificateFormat::PEM:
+ return fromPem(cert);
+ case RpcCertificateFormat::DER:
+ return fromDer(cert);
+ }
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format) {
+ bssl::UniquePtr<BIO> certBio(BIO_new(BIO_s_mem()));
+ switch (format) {
+ case RpcCertificateFormat::PEM: {
+ TEST_AND_RETURN({}, PEM_write_bio_X509(certBio.get(), x509));
+ } break;
+ case RpcCertificateFormat::DER: {
+ TEST_AND_RETURN({}, i2d_X509_bio(certBio.get(), x509));
+ } break;
+ default: {
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+ }
+ }
+ const uint8_t* data;
+ size_t len;
+ TEST_AND_RETURN({}, BIO_mem_contents(certBio.get(), &data, &len));
+ return std::vector<uint8_t>(data, data + len);
+}
+
+} // namespace android
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index ad9ba96..5733993 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -23,6 +23,8 @@
#include <thread>
#include <vector>
+#include <android-base/file.h>
+#include <android-base/hex.h>
#include <android-base/scopeguard.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
@@ -139,20 +141,11 @@
return ret;
}
-std::string RpcServer::getCertificate(CertificateFormat format) {
+std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
std::lock_guard<std::mutex> _l(mLock);
return mCtx->getCertificate(format);
}
-status_t RpcServer::addTrustedPeerCertificate(CertificateFormat format, std::string_view cert) {
- std::lock_guard<std::mutex> _l(mLock);
- // Ensure that join thread is not running or shutdown trigger is not set up. In either case,
- // it means there are child threads running. It is invalid to add trusted peer certificates
- // after join thread and/or child threads are running to avoid race condition.
- if (mJoinThreadRunning || mShutdownTrigger != nullptr) return INVALID_OPERATION;
- return mCtx->addTrustedPeerCertificate(format, cert);
-}
-
static void joinRpcServer(sp<RpcServer>&& thiz) {
thiz->join();
}
@@ -290,17 +283,29 @@
}
}
+ std::vector<uint8_t> sessionId;
+ if (status == OK) {
+ if (header.sessionIdSize > 0) {
+ sessionId.resize(header.sessionIdSize);
+ status = client->interruptableReadFully(server->mShutdownTrigger.get(),
+ sessionId.data(), sessionId.size());
+ if (status != OK) {
+ ALOGE("Failed to read session ID for client connecting to RPC server: %s",
+ statusToString(status).c_str());
+ // still need to cleanup before we can return
+ }
+ }
+ }
+
bool incoming = false;
uint32_t protocolVersion = 0;
- RpcAddress sessionId = RpcAddress::zero();
bool requestingNewSession = false;
if (status == OK) {
incoming = header.options & RPC_CONNECTION_OPTION_INCOMING;
protocolVersion = std::min(header.version,
server->mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION));
- sessionId = RpcAddress::fromRawEmbedded(&header.sessionId);
- requestingNewSession = sessionId.isZero();
+ requestingNewSession = sessionId.empty();
if (requestingNewSession) {
RpcNewSessionResponse response{
@@ -342,15 +347,26 @@
return;
}
+ // Uniquely identify session at the application layer. Even if a
+ // client/server use the same certificates, if they create multiple
+ // sessions, we still want to distinguish between them.
+ constexpr size_t kSessionIdSize = 32;
+ sessionId.resize(kSessionIdSize);
size_t tries = 0;
do {
// don't block if there is some entropy issue
if (tries++ > 5) {
- ALOGE("Cannot find new address: %s", sessionId.toString().c_str());
+ ALOGE("Cannot find new address: %s",
+ base::HexString(sessionId.data(), sessionId.size()).c_str());
return;
}
- sessionId = RpcAddress::random(true /*forServer*/);
+ base::unique_fd fd(TEMP_FAILURE_RETRY(
+ open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
+ if (!base::ReadFully(fd, sessionId.data(), sessionId.size())) {
+ ALOGE("Could not read from /dev/urandom to create session ID");
+ return;
+ }
} while (server->mSessions.end() != server->mSessions.find(sessionId));
session = RpcSession::make();
@@ -370,7 +386,7 @@
auto it = server->mSessions.find(sessionId);
if (it == server->mSessions.end()) {
ALOGE("Cannot add thread, no record of session with ID %s",
- sessionId.toString().c_str());
+ base::HexString(sessionId.data(), sessionId.size()).c_str());
return;
}
session = it->second;
@@ -432,16 +448,17 @@
}
void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
- auto id = session->mId;
- LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
- LOG_RPC_DETAIL("Dropping session with address %s", id->toString().c_str());
+ const std::vector<uint8_t>& id = session->mId;
+ LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID");
+ LOG_RPC_DETAIL("Dropping session with address %s",
+ base::HexString(id.data(), id.size()).c_str());
std::lock_guard<std::mutex> _l(mLock);
- auto it = mSessions.find(*id);
+ auto it = mSessions.find(id);
LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s",
- id->toString().c_str());
+ base::HexString(id.data(), id.size()).c_str());
LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %s",
- id->toString().c_str());
+ base::HexString(id.data(), id.size()).c_str());
(void)mSessions.erase(it);
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index c57b749..38958c9 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -26,8 +26,10 @@
#include <string_view>
+#include <android-base/hex.h>
#include <android-base/macros.h>
#include <android_runtime/vm.h>
+#include <binder/BpBinder.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <binder/RpcTransportRaw.h>
@@ -64,23 +66,12 @@
sp<RpcSession> RpcSession::make() {
// Default is without TLS.
- return make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+ return make(RpcTransportCtxFactoryRaw::make());
}
-sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
- std::optional<CertificateFormat> serverCertificateFormat,
- std::optional<std::string> serverCertificate) {
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
auto ctx = rpcTransportCtxFactory->newClientCtx();
if (ctx == nullptr) return nullptr;
- LOG_ALWAYS_FATAL_IF(serverCertificateFormat.has_value() != serverCertificate.has_value());
- if (serverCertificateFormat.has_value() && serverCertificate.has_value()) {
- status_t status =
- ctx->addTrustedPeerCertificate(*serverCertificateFormat, *serverCertificate);
- if (status != OK) {
- ALOGE("Cannot add trusted server certificate: %s", statusToString(status).c_str());
- return nullptr;
- }
- }
return sp<RpcSession>::make(std::move(ctx));
}
@@ -143,7 +134,7 @@
}
status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
- return setupClient([&](const RpcAddress& sessionId, bool incoming) -> status_t {
+ return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
// std::move'd from fd becomes -1 (!ok())
if (!fd.ok()) {
fd = request();
@@ -201,7 +192,7 @@
if (wait) {
LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
- mShutdownListener->waitForShutdown(_l);
+ mShutdownListener->waitForShutdown(_l, sp<RpcSession>::fromExisting(this));
LOG_ALWAYS_FATAL_IF(!mThreads.empty(), "Shutdown failed");
}
@@ -225,7 +216,11 @@
sp<RpcSession>::fromExisting(this), reply, flags);
}
-status_t RpcSession::sendDecStrong(const RpcAddress& address) {
+status_t RpcSession::sendDecStrong(const BpBinder* binder) {
+ return sendDecStrong(binder->getPrivateAccessor().rpcAddress());
+}
+
+status_t RpcSession::sendDecStrong(uint64_t address) {
ExclusiveConnection connection;
status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
ConnectionUse::CLIENT_REFCOUNT, &connection);
@@ -244,29 +239,30 @@
ConnectionUse::CLIENT, &connection);
if (status != OK) return status;
- mId = RpcAddress::zero();
- status = state()->getSessionId(connection.get(), sp<RpcSession>::fromExisting(this),
- &mId.value());
+ status = state()->getSessionId(connection.get(), sp<RpcSession>::fromExisting(this), &mId);
if (status != OK) return status;
- LOG_RPC_DETAIL("RpcSession %p has id %s", this, mId->toString().c_str());
+ LOG_RPC_DETAIL("RpcSession %p has id %s", this,
+ base::HexString(mId.data(), mId.size()).c_str());
return OK;
}
void RpcSession::WaitForShutdownListener::onSessionAllIncomingThreadsEnded(
const sp<RpcSession>& session) {
(void)session;
- mShutdown = true;
}
void RpcSession::WaitForShutdownListener::onSessionIncomingThreadEnded() {
mCv.notify_all();
}
-void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock) {
- while (!mShutdown) {
+void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
+ const sp<RpcSession>& session) {
+ while (session->mIncomingConnections.size() > 0) {
if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
- ALOGE("Waiting for RpcSession to shut down (1s w/o progress).");
+ ALOGE("Waiting for RpcSession to shut down (1s w/o progress): %zu incoming connections "
+ "still.",
+ session->mIncomingConnections.size());
}
}
}
@@ -408,8 +404,8 @@
return server;
}
-status_t RpcSession::setupClient(
- const std::function<status_t(const RpcAddress& sessionId, bool incoming)>& connectAndInit) {
+status_t RpcSession::setupClient(const std::function<status_t(const std::vector<uint8_t>& sessionId,
+ bool incoming)>& connectAndInit) {
{
std::lock_guard<std::mutex> _l(mMutex);
LOG_ALWAYS_FATAL_IF(mOutgoingConnections.size() != 0,
@@ -418,8 +414,7 @@
}
if (auto status = initShutdownTrigger(); status != OK) return status;
- if (status_t status = connectAndInit(RpcAddress::zero(), false /*incoming*/); status != OK)
- return status;
+ if (status_t status = connectAndInit({}, false /*incoming*/); status != OK) return status;
{
ExclusiveConnection connection;
@@ -460,26 +455,25 @@
// we've already setup one client
for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
- if (status_t status = connectAndInit(mId.value(), false /*incoming*/); status != OK)
- return status;
+ if (status_t status = connectAndInit(mId, false /*incoming*/); status != OK) return status;
}
for (size_t i = 0; i < mMaxThreads; i++) {
- if (status_t status = connectAndInit(mId.value(), true /*incoming*/); status != OK)
- return status;
+ if (status_t status = connectAndInit(mId, true /*incoming*/); status != OK) return status;
}
return OK;
}
status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
- return setupClient([&](const RpcAddress& sessionId, bool incoming) {
+ return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) {
return setupOneSocketConnection(addr, sessionId, incoming);
});
}
status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
- const RpcAddress& sessionId, bool incoming) {
+ const std::vector<uint8_t>& sessionId,
+ bool incoming) {
for (size_t tries = 0; tries < 5; tries++) {
if (tries > 0) usleep(10000);
@@ -537,7 +531,7 @@
return UNKNOWN_ERROR;
}
-status_t RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId,
+status_t RpcSession::initAndAddConnection(unique_fd fd, const std::vector<uint8_t>& sessionId,
bool incoming) {
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
auto server = mCtx->newTransport(std::move(fd), mShutdownTrigger.get());
@@ -548,13 +542,20 @@
LOG_RPC_DETAIL("Socket at client with RpcTransport %p", server.get());
+ if (sessionId.size() > std::numeric_limits<uint16_t>::max()) {
+ ALOGE("Session ID too big %zu", sessionId.size());
+ return BAD_VALUE;
+ }
+
RpcConnectionHeader header{
.version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
.options = 0,
+ .sessionIdSize = static_cast<uint16_t>(sessionId.size()),
};
- memcpy(&header.sessionId, &sessionId.viewRawEmbedded(), sizeof(RpcWireAddress));
- if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
+ if (incoming) {
+ header.options |= RPC_CONNECTION_OPTION_INCOMING;
+ }
auto sendHeaderStatus =
server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header));
@@ -564,6 +565,18 @@
return sendHeaderStatus;
}
+ if (sessionId.size() > 0) {
+ auto sendSessionIdStatus =
+ server->interruptableWriteFully(mShutdownTrigger.get(), sessionId.data(),
+ sessionId.size());
+ if (sendSessionIdStatus != OK) {
+ ALOGE("Could not write session ID ('%s') to socket: %s",
+ base::HexString(sessionId.data(), sessionId.size()).c_str(),
+ statusToString(sendSessionIdStatus).c_str());
+ return sendSessionIdStatus;
+ }
+ }
+
LOG_RPC_DETAIL("Socket at client: header sent");
if (incoming) {
@@ -636,7 +649,7 @@
}
bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
- const RpcAddress& sessionId) {
+ const std::vector<uint8_t>& sessionId) {
LOG_ALWAYS_FATAL_IF(mForServer != nullptr);
LOG_ALWAYS_FATAL_IF(server == nullptr);
LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
@@ -697,7 +710,7 @@
return false;
}
-std::string RpcSession::getCertificate(CertificateFormat format) {
+std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
return mCtx->getCertificate(format);
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index b58f1b3..11a083a 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -52,11 +52,11 @@
RpcState::~RpcState() {}
status_t RpcState::onBinderLeaving(const sp<RpcSession>& session, const sp<IBinder>& binder,
- RpcAddress* outAddress) {
+ uint64_t* outAddress) {
bool isRemote = binder->remoteBinder();
bool isRpc = isRemote && binder->remoteBinder()->isRpcBinder();
- if (isRpc && binder->remoteBinder()->getPrivateAccessorForId().rpcSession() != session) {
+ if (isRpc && binder->remoteBinder()->getPrivateAccessor().rpcSession() != session) {
// We need to be able to send instructions over the socket for how to
// connect to a different server, and we also need to let the host
// process know that this is happening.
@@ -84,12 +84,10 @@
for (auto& [addr, node] : mNodeForAddress) {
if (binder == node.binder) {
if (isRpc) {
- const RpcAddress& actualAddr =
- binder->remoteBinder()->getPrivateAccessorForId().rpcAddress();
- // TODO(b/182939933): this is only checking integrity of data structure
- // a different data structure doesn't need this
- LOG_ALWAYS_FATAL_IF(addr < actualAddr, "Address mismatch");
- LOG_ALWAYS_FATAL_IF(actualAddr < addr, "Address mismatch");
+ // check integrity of data structure
+ uint64_t actualAddr = binder->remoteBinder()->getPrivateAccessor().rpcAddress();
+ LOG_ALWAYS_FATAL_IF(addr != actualAddr, "Address mismatch %" PRIu64 " vs %" PRIu64,
+ addr, actualAddr);
}
node.timesSent++;
node.sentRef = binder; // might already be set
@@ -101,8 +99,29 @@
bool forServer = session->server() != nullptr;
- for (size_t tries = 0; tries < 5; tries++) {
- auto&& [it, inserted] = mNodeForAddress.insert({RpcAddress::random(forServer),
+ // arbitrary limit for maximum number of nodes in a process (otherwise we
+ // might run out of addresses)
+ if (mNodeForAddress.size() > 100000) {
+ return NO_MEMORY;
+ }
+
+ while (true) {
+ RpcWireAddress address{
+ .options = RPC_WIRE_ADDRESS_OPTION_CREATED,
+ .address = mNextId,
+ };
+ if (forServer) {
+ address.options |= RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
+ }
+
+ // avoid ubsan abort
+ if (mNextId >= std::numeric_limits<uint32_t>::max()) {
+ mNextId = 0;
+ } else {
+ mNextId++;
+ }
+
+ auto&& [it, inserted] = mNodeForAddress.insert({RpcWireAddress::toRaw(address),
BinderNode{
.binder = binder,
.timesSent = 1,
@@ -112,18 +131,10 @@
*outAddress = it->first;
return OK;
}
-
- // well, we don't have visibility into the header here, but still
- static_assert(sizeof(RpcWireAddress) == 40, "this log needs updating");
- ALOGW("2**256 is 1e77. If you see this log, you probably have some entropy issue, or maybe "
- "you witness something incredible!");
}
-
- ALOGE("Unable to create an address in order to send out %p", binder.get());
- return WOULD_BLOCK;
}
-status_t RpcState::onBinderEntering(const sp<RpcSession>& session, const RpcAddress& address,
+status_t RpcState::onBinderEntering(const sp<RpcSession>& session, uint64_t address,
sp<IBinder>* out) {
// ensure that: if we want to use addresses for something else in the future (for
// instance, allowing transitive binder sends), that we don't accidentally
@@ -133,8 +144,11 @@
// if we communicate with a binder, it could always be proxying
// information. However, we want to make sure that isn't done on accident
// by a client.
- if (!address.isRecognizedType()) {
- ALOGE("Address is of an unknown type, rejecting: %s", address.toString().c_str());
+ RpcWireAddress addr = RpcWireAddress::fromRaw(address);
+ constexpr uint32_t kKnownOptions =
+ RPC_WIRE_ADDRESS_OPTION_CREATED | RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
+ if (addr.options & ~kKnownOptions) {
+ ALOGE("Address is of an unknown type, rejecting: %" PRIu64, address);
return BAD_VALUE;
}
@@ -159,9 +173,9 @@
// we don't know about this binder, so the other side of the connection
// should have created it.
- if (address.isForServer() == !!session->server()) {
- ALOGE("Server received unrecognized address which we should own the creation of %s.",
- address.toString().c_str());
+ if ((addr.options & RPC_WIRE_ADDRESS_OPTION_FOR_SERVER) == !!session->server()) {
+ ALOGE("Server received unrecognized address which we should own the creation of %" PRIu64,
+ address);
return BAD_VALUE;
}
@@ -170,7 +184,7 @@
// Currently, all binders are assumed to be part of the same session (no
// device global binders in the RPC world).
- it->second.binder = *out = BpBinder::create(session, it->first);
+ it->second.binder = *out = BpBinder::PrivateAccessor::create(session, it->first);
it->second.timesRecd = 1;
return OK;
}
@@ -241,9 +255,8 @@
desc = "(null)";
}
- ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a:%s type:%s",
- node.binder.unsafe_get(), node.timesSent, node.timesRecd, address.toString().c_str(),
- desc);
+ ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a: %" PRIu64 " type: %s",
+ node.binder.unsafe_get(), node.timesSent, node.timesRecd, address, desc);
}
ALOGE("END DUMP OF RpcState");
}
@@ -360,8 +373,8 @@
data.markForRpc(session);
Parcel reply;
- status_t status = transactAddress(connection, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_ROOT,
- data, session, &reply, 0);
+ status_t status =
+ transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_ROOT, data, session, &reply, 0);
if (status != OK) {
ALOGE("Error getting root object: %s", statusToString(status).c_str());
return nullptr;
@@ -376,9 +389,8 @@
data.markForRpc(session);
Parcel reply;
- status_t status =
- transactAddress(connection, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_MAX_THREADS,
- data, session, &reply, 0);
+ status_t status = transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, data,
+ session, &reply, 0);
if (status != OK) {
ALOGE("Error getting max threads: %s", statusToString(status).c_str());
return status;
@@ -397,20 +409,19 @@
}
status_t RpcState::getSessionId(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, RpcAddress* sessionIdOut) {
+ const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut) {
Parcel data;
data.markForRpc(session);
Parcel reply;
- status_t status =
- transactAddress(connection, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_SESSION_ID,
- data, session, &reply, 0);
+ status_t status = transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_SESSION_ID, data,
+ session, &reply, 0);
if (status != OK) {
ALOGE("Error getting session ID: %s", statusToString(status).c_str());
return status;
}
- return sessionIdOut->readFromParcel(reply);
+ return reply.readByteVector(sessionIdOut);
}
status_t RpcState::transact(const sp<RpcSession::RpcConnection>& connection,
@@ -426,26 +437,26 @@
return BAD_TYPE;
}
- RpcAddress address = RpcAddress::zero();
+ uint64_t address;
if (status_t status = onBinderLeaving(session, binder, &address); status != OK) return status;
return transactAddress(connection, address, code, data, session, reply, flags);
}
status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connection,
- const RpcAddress& address, uint32_t code, const Parcel& data,
+ uint64_t address, uint32_t code, const Parcel& data,
const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
LOG_ALWAYS_FATAL_IF(!data.isForRpc());
LOG_ALWAYS_FATAL_IF(data.objectsCount() != 0);
uint64_t asyncNumber = 0;
- if (!address.isZero()) {
+ if (address != 0) {
std::unique_lock<std::mutex> _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(address);
- LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending transact on unknown address %s",
- address.toString().c_str());
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
+ "Sending transact on unknown address %" PRIu64, address);
if (flags & IBinder::FLAG_ONEWAY) {
asyncNumber = it->second.asyncNumber;
@@ -466,8 +477,9 @@
.command = RPC_COMMAND_TRANSACT,
.bodySize = static_cast<uint32_t>(sizeof(RpcWireTransaction) + data.dataSize()),
};
+
RpcWireTransaction transaction{
- .address = address.viewRawEmbedded(),
+ .address = RpcWireAddress::fromRaw(address),
.code = code,
.flags = flags,
.asyncNumber = asyncNumber,
@@ -557,15 +569,14 @@
}
status_t RpcState::sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const RpcAddress& addr) {
+ const sp<RpcSession>& session, uint64_t addr) {
{
std::lock_guard<std::mutex> _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(addr);
- LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending dec strong on unknown address %s",
- addr.toString().c_str());
- LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %s",
- addr.toString().c_str());
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
+ "Sending dec strong on unknown address %" PRIu64, addr);
+ LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %" PRIu64, addr);
it->second.timesRecd--;
LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
@@ -579,8 +590,7 @@
if (status_t status = rpcSend(connection, session, "dec ref header", &cmd, sizeof(cmd));
status != OK)
return status;
- if (status_t status = rpcSend(connection, session, "dec ref body", &addr.viewRawEmbedded(),
- sizeof(RpcWireAddress));
+ if (status_t status = rpcSend(connection, session, "dec ref body", &addr, sizeof(addr));
status != OK)
return status;
return OK;
@@ -685,14 +695,12 @@
}
RpcWireTransaction* transaction = reinterpret_cast<RpcWireTransaction*>(transactionData.data());
- // TODO(b/182939933): heap allocation just for lookup in mNodeForAddress,
- // maybe add an RpcAddress 'view' if the type remains 'heavy'
- auto addr = RpcAddress::fromRawEmbedded(&transaction->address);
+ uint64_t addr = RpcWireAddress::toRaw(transaction->address);
bool oneway = transaction->flags & IBinder::FLAG_ONEWAY;
status_t replyStatus = OK;
sp<IBinder> target;
- if (!addr.isZero()) {
+ if (addr != 0) {
if (!targetRef) {
replyStatus = onBinderEntering(session, addr, &target);
} else {
@@ -708,21 +716,21 @@
// (any binder which is being transacted on should be holding a
// strong ref count), so in either case, terminating the
// session.
- ALOGE("While transacting, binder has been deleted at address %s. Terminating!",
- addr.toString().c_str());
+ ALOGE("While transacting, binder has been deleted at address %" PRIu64 ". Terminating!",
+ addr);
(void)session->shutdownAndWait(false);
replyStatus = BAD_VALUE;
} else if (target->localBinder() == nullptr) {
- ALOGE("Unknown binder address or non-local binder, not address %s. Terminating!",
- addr.toString().c_str());
+ ALOGE("Unknown binder address or non-local binder, not address %" PRIu64
+ ". Terminating!",
+ addr);
(void)session->shutdownAndWait(false);
replyStatus = BAD_VALUE;
} else if (oneway) {
std::unique_lock<std::mutex> _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
if (it->second.binder.promote() != target) {
- ALOGE("Binder became invalid during transaction. Bad client? %s",
- addr.toString().c_str());
+ ALOGE("Binder became invalid during transaction. Bad client? %" PRIu64, addr);
replyStatus = BAD_VALUE;
} else if (transaction->asyncNumber != it->second.asyncNumber) {
// we need to process some other asynchronous transaction
@@ -734,8 +742,8 @@
});
size_t numPending = it->second.asyncTodo.size();
- LOG_RPC_DETAIL("Enqueuing %" PRId64 " on %s (%zu pending)",
- transaction->asyncNumber, addr.toString().c_str(), numPending);
+ LOG_RPC_DETAIL("Enqueuing %" PRIu64 " on %" PRIu64 " (%zu pending)",
+ transaction->asyncNumber, addr, numPending);
constexpr size_t kArbitraryOnewayCallTerminateLevel = 10000;
constexpr size_t kArbitraryOnewayCallWarnLevel = 1000;
@@ -792,7 +800,7 @@
// for client connections, this should always report the value
// originally returned from the server, so this is asserting
// that it exists
- replyStatus = session->mId.value().writeToParcel(&reply);
+ replyStatus = reply.writeByteVector(session->mId);
break;
}
default: {
@@ -820,8 +828,8 @@
ALOGW("Oneway call failed with error: %d", replyStatus);
}
- LOG_RPC_DETAIL("Processed async transaction %" PRId64 " on %s", transaction->asyncNumber,
- addr.toString().c_str());
+ LOG_RPC_DETAIL("Processed async transaction %" PRIu64 " on %" PRIu64,
+ transaction->asyncNumber, addr);
// Check to see if there is another asynchronous transaction to process.
// This behavior differs from binder behavior, since in the binder
@@ -847,8 +855,8 @@
if (it->second.asyncTodo.size() == 0) return OK;
if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) {
- LOG_RPC_DETAIL("Found next async transaction %" PRId64 " on %s",
- it->second.asyncNumber, addr.toString().c_str());
+ LOG_RPC_DETAIL("Found next async transaction %" PRIu64 " on %" PRIu64,
+ it->second.asyncNumber, addr);
// justification for const_cast (consider avoiding priority_queue):
// - AsyncTodo operator< doesn't depend on 'data' or 'ref' objects
@@ -904,7 +912,7 @@
status != OK)
return status;
- if (command.bodySize < sizeof(RpcWireAddress)) {
+ if (command.bodySize != sizeof(RpcWireAddress)) {
ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
sizeof(RpcWireAddress), command.bodySize);
(void)session->shutdownAndWait(false);
@@ -912,31 +920,32 @@
}
RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
- // TODO(b/182939933): heap allocation just for lookup
- auto addr = RpcAddress::fromRawEmbedded(address);
+ uint64_t addr = RpcWireAddress::toRaw(*address);
+
std::unique_lock<std::mutex> _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
- ALOGE("Unknown binder address %s for dec strong.", addr.toString().c_str());
+ ALOGE("Unknown binder address %" PRIu64 " for dec strong.", addr);
return OK;
}
sp<IBinder> target = it->second.binder.promote();
if (target == nullptr) {
- ALOGE("While requesting dec strong, binder has been deleted at address %s. Terminating!",
- addr.toString().c_str());
+ ALOGE("While requesting dec strong, binder has been deleted at address %" PRIu64
+ ". Terminating!",
+ addr);
_l.unlock();
(void)session->shutdownAndWait(false);
return BAD_VALUE;
}
if (it->second.timesSent == 0) {
- ALOGE("No record of sending binder, but requested decStrong: %s", addr.toString().c_str());
+ ALOGE("No record of sending binder, but requested decStrong: %" PRIu64, addr);
return OK;
}
- LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %s",
- addr.toString().c_str());
+ LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
+ addr);
it->second.timesSent--;
sp<IBinder> tempHold = tryEraseNode(it);
@@ -946,7 +955,7 @@
return OK;
}
-sp<IBinder> RpcState::tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& it) {
+sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) {
sp<IBinder> ref;
if (it->second.timesSent == 0) {
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 1446eec..dcfb569 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -73,17 +73,17 @@
status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, size_t* maxThreadsOut);
status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, RpcAddress* sessionIdOut);
+ const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut);
[[nodiscard]] status_t transact(const sp<RpcSession::RpcConnection>& connection,
const sp<IBinder>& address, uint32_t code, const Parcel& data,
const sp<RpcSession>& session, Parcel* reply, uint32_t flags);
[[nodiscard]] status_t transactAddress(const sp<RpcSession::RpcConnection>& connection,
- const RpcAddress& address, uint32_t code,
- const Parcel& data, const sp<RpcSession>& session,
- Parcel* reply, uint32_t flags);
+ uint64_t address, uint32_t code, const Parcel& data,
+ const sp<RpcSession>& session, Parcel* reply,
+ uint32_t flags);
[[nodiscard]] status_t sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const RpcAddress& address);
+ const sp<RpcSession>& session, uint64_t address);
enum class CommandType {
ANY,
@@ -99,15 +99,15 @@
* ownership to the outgoing binder.
*/
[[nodiscard]] status_t onBinderLeaving(const sp<RpcSession>& session, const sp<IBinder>& binder,
- RpcAddress* outAddress);
+ uint64_t* outAddress);
/**
* Called by Parcel for incoming binders. This either returns the refcount
* to the process, if this process already has one, or it takes ownership of
* that refcount
*/
- [[nodiscard]] status_t onBinderEntering(const sp<RpcSession>& session,
- const RpcAddress& address, sp<IBinder>* out);
+ [[nodiscard]] status_t onBinderEntering(const sp<RpcSession>& session, uint64_t address,
+ sp<IBinder>* out);
size_t countBinders();
void dump();
@@ -221,15 +221,16 @@
// happens, and there is a strong reference to the binder kept by
// binderNode, this returns that strong reference, so that it can be
// dropped after any locks are removed.
- sp<IBinder> tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& it);
+ sp<IBinder> tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it);
// true - success
// false - session shutdown, halt
[[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node);
std::mutex mNodeMutex;
bool mTerminated = false;
+ uint32_t mNextId = 0;
// binders known by both sides of a session
- std::map<RpcAddress, BinderNode> mNodeForAddress;
+ std::map<uint64_t, BinderNode> mNodeForAddress;
};
} // namespace android
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 930df12..c012df8 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -111,8 +111,7 @@
std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
return std::make_unique<RpcTransportRaw>(std::move(fd));
}
- std::string getCertificate(CertificateFormat) const override { return {}; }
- status_t addTrustedPeerCertificate(CertificateFormat, std::string_view) override { return OK; }
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
};
} // namespace
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index e6cb04e..63f9339 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -22,10 +22,12 @@
#include <openssl/bn.h>
#include <openssl/ssl.h>
+#include <binder/RpcCertificateUtils.h>
#include <binder/RpcTransportTls.h>
#include "FdTrigger.h"
#include "RpcState.h"
+#include "Utils.h"
#define SHOULD_LOG_TLS_DETAIL false
@@ -35,14 +37,6 @@
#define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
#endif
-#define TEST_AND_RETURN(value, expr) \
- do { \
- if (!(expr)) { \
- ALOGE("Failed to call: %s", #expr); \
- return value; \
- } \
- } while (0)
-
using android::base::ErrnoError;
using android::base::Error;
using android::base::Result;
@@ -353,7 +347,7 @@
ALOGE("%s: %s", __PRETTY_FUNCTION__, ret.error().message().c_str());
return ret.error().code() == 0 ? UNKNOWN_ERROR : -ret.error().code();
}
- return OK;
+ return *ret ? -ECANCELED : OK;
}
status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, const void* data,
@@ -453,31 +447,54 @@
public:
template <typename Impl,
typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>>
- static std::unique_ptr<RpcTransportCtxTls> create();
+ static std::unique_ptr<RpcTransportCtxTls> create(
+ std::shared_ptr<RpcCertificateVerifier> verifier);
std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
FdTrigger* fdTrigger) const override;
- std::string getCertificate(CertificateFormat) const override;
- status_t addTrustedPeerCertificate(CertificateFormat, std::string_view cert) override;
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override;
protected:
+ static ssl_verify_result_t sslCustomVerify(SSL* ssl, uint8_t* outAlert);
virtual void preHandshake(Ssl* ssl) const = 0;
bssl::UniquePtr<SSL_CTX> mCtx;
+ std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
};
-std::string RpcTransportCtxTls::getCertificate(CertificateFormat) const {
- // TODO(b/195166979): return certificate here
- return {};
+std::vector<uint8_t> RpcTransportCtxTls::getCertificate(RpcCertificateFormat format) const {
+ X509* x509 = SSL_CTX_get0_certificate(mCtx.get()); // does not own
+ return serializeCertificate(x509, format);
}
-status_t RpcTransportCtxTls::addTrustedPeerCertificate(CertificateFormat, std::string_view) {
- // TODO(b/195166979): set certificate here
- return OK;
+// Verify by comparing the leaf of peer certificate with every certificate in
+// mTrustedPeerCertificates. Does not support certificate chains.
+ssl_verify_result_t RpcTransportCtxTls::sslCustomVerify(SSL* ssl, uint8_t* outAlert) {
+ LOG_ALWAYS_FATAL_IF(outAlert == nullptr);
+ const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+
+ bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
+ LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
+ "%s: libssl should not ask to verify non-existing cert", logPrefix);
+
+ auto ctx = SSL_get_SSL_CTX(ssl); // Does not set error queue
+ LOG_ALWAYS_FATAL_IF(ctx == nullptr);
+ // void* -> RpcTransportCtxTls*
+ auto rpcTransportCtxTls = reinterpret_cast<RpcTransportCtxTls*>(SSL_CTX_get_app_data(ctx));
+ LOG_ALWAYS_FATAL_IF(rpcTransportCtxTls == nullptr);
+
+ status_t verifyStatus = rpcTransportCtxTls->mCertVerifier->verify(peerCert.get(), outAlert);
+ if (verifyStatus == OK) {
+ return ssl_verify_ok;
+ }
+ LOG_TLS_DETAIL("%s: Failed to verify client: status = %s, alert = %s", logPrefix,
+ statusToString(verifyStatus).c_str(), SSL_alert_desc_string_long(*outAlert));
+ return ssl_verify_invalid;
}
// Common implementation for creating server and client contexts. The child class, |Impl|, is
// provided as a template argument so that this function can initialize an |Impl| object.
template <typename Impl, typename>
-std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create() {
+std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create(
+ std::shared_ptr<RpcCertificateVerifier> verifier) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
TEST_AND_RETURN(nullptr, ctx != nullptr);
@@ -488,10 +505,10 @@
TEST_AND_RETURN(nullptr, SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get()));
TEST_AND_RETURN(nullptr, SSL_CTX_use_certificate(ctx.get(), cert.get()));
- // TODO(b/195166979): peer should send certificate in a different channel, and this class
- // should verify it here.
- SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER,
- [](SSL*, uint8_t*) -> ssl_verify_result_t { return ssl_verify_ok; });
+ // Enable two-way authentication by setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT on server.
+ // Client ignores SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag.
+ SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ sslCustomVerify);
// Require at least TLS 1.3
TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
@@ -501,7 +518,10 @@
}
auto ret = std::make_unique<Impl>();
+ // RpcTransportCtxTls* -> void*
+ TEST_AND_RETURN(nullptr, SSL_CTX_set_app_data(ctx.get(), reinterpret_cast<void*>(ret.get())));
ret->mCtx = std::move(ctx);
+ ret->mCertVerifier = std::move(verifier);
return ret;
}
@@ -533,19 +553,25 @@
} // namespace
std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
- return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>();
+ return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier);
}
std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
- return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>();
+ return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier);
}
const char* RpcTransportCtxFactoryTls::toCString() const {
return "tls";
}
-std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make() {
- return std::unique_ptr<RpcTransportCtxFactoryTls>(new RpcTransportCtxFactoryTls());
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make(
+ std::shared_ptr<RpcCertificateVerifier> verifier) {
+ if (verifier == nullptr) {
+ ALOGE("%s: Must provide a certificate verifier", __PRETTY_FUNCTION__);
+ return nullptr;
+ }
+ return std::unique_ptr<RpcTransportCtxFactoryTls>(
+ new RpcTransportCtxFactoryTls(std::move(verifier)));
}
} // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 067c4ad..a87aa07 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -20,18 +20,23 @@
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wpadded"
-enum : uint8_t {
- RPC_CONNECTION_OPTION_INCOMING = 0x1, // default is outgoing
-};
+constexpr uint8_t RPC_CONNECTION_OPTION_INCOMING = 0x1; // default is outgoing
-constexpr uint64_t RPC_WIRE_ADDRESS_OPTION_CREATED = 1 << 0; // distinguish from '0' address
-constexpr uint64_t RPC_WIRE_ADDRESS_OPTION_FOR_SERVER = 1 << 1;
+constexpr uint32_t RPC_WIRE_ADDRESS_OPTION_CREATED = 1 << 0; // distinguish from '0' address
+constexpr uint32_t RPC_WIRE_ADDRESS_OPTION_FOR_SERVER = 1 << 1;
struct RpcWireAddress {
- uint64_t options;
- uint8_t address[32];
+ uint32_t options;
+ uint32_t address;
+
+ static inline RpcWireAddress fromRaw(uint64_t raw) {
+ return *reinterpret_cast<RpcWireAddress*>(&raw);
+ }
+ static inline uint64_t toRaw(RpcWireAddress addr) {
+ return *reinterpret_cast<uint64_t*>(&addr);
+ }
};
-static_assert(sizeof(RpcWireAddress) == 40);
+static_assert(sizeof(RpcWireAddress) == sizeof(uint64_t));
/**
* This is sent to an RpcServer in order to request a new connection is created,
@@ -39,12 +44,13 @@
*/
struct RpcConnectionHeader {
uint32_t version; // maximum supported by caller
- uint8_t reserver0[4];
- RpcWireAddress sessionId;
uint8_t options;
- uint8_t reserved1[7];
+ uint8_t reservered[9];
+ // Follows is sessionIdSize bytes.
+ // if size is 0, this is requesting a new session.
+ uint16_t sessionIdSize;
};
-static_assert(sizeof(RpcConnectionHeader) == 56);
+static_assert(sizeof(RpcConnectionHeader) == 16);
/**
* In response to an RpcConnectionHeader which corresponds to a new session,
@@ -122,7 +128,7 @@
uint8_t data[];
};
-static_assert(sizeof(RpcWireTransaction) == 72);
+static_assert(sizeof(RpcWireTransaction) == 40);
struct RpcWireReply {
int32_t status; // transact return
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 1e383da..ff2fad8 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -19,6 +19,15 @@
#include <android-base/result.h>
#include <android-base/unique_fd.h>
+#include <log/log.h>
+
+#define TEST_AND_RETURN(value, expr) \
+ do { \
+ if (!(expr)) { \
+ ALOGE("Failed to call: %s", #expr); \
+ return value; \
+ } \
+ } while (0)
namespace android {
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index 9dea3b4..793795e 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -74,6 +74,8 @@
//
// Indicates whether the process has received any sync calls since last
// freeze (cleared at freeze/unfreeze)
+ // bit 0: received sync transaction after being frozen
+ // bit 1: new pending sync transaction during freezing
//
__u32 sync_recv;
//
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index a6d35c7..c0454b6 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -17,7 +17,6 @@
#pragma once
#include <binder/IBinder.h>
-#include <binder/RpcAddress.h>
#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include <utils/threads.h>
@@ -40,9 +39,6 @@
class BpBinder : public IBinder
{
public:
- static sp<BpBinder> create(int32_t handle);
- static sp<BpBinder> create(const sp<RpcSession>& session, const RpcAddress& address);
-
/**
* Return value:
* true - this is associated with a socket RpcSession
@@ -117,42 +113,49 @@
KeyedVector<const void*, entry_t> mObjects;
};
- class PrivateAccessorForId {
+ class PrivateAccessor {
private:
friend class BpBinder;
friend class ::android::Parcel;
friend class ::android::ProcessState;
+ friend class ::android::RpcSession;
friend class ::android::RpcState;
- explicit PrivateAccessorForId(const BpBinder* binder) : mBinder(binder) {}
+ explicit PrivateAccessor(const BpBinder* binder) : mBinder(binder) {}
+
+ static sp<BpBinder> create(int32_t handle) { return BpBinder::create(handle); }
+ static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address) {
+ return BpBinder::create(session, address);
+ }
// valid if !isRpcBinder
int32_t binderHandle() const { return mBinder->binderHandle(); }
// valid if isRpcBinder
- const RpcAddress& rpcAddress() const { return mBinder->rpcAddress(); }
+ uint64_t rpcAddress() const { return mBinder->rpcAddress(); }
const sp<RpcSession>& rpcSession() const { return mBinder->rpcSession(); }
const BpBinder* mBinder;
};
- const PrivateAccessorForId getPrivateAccessorForId() const {
- return PrivateAccessorForId(this);
- }
+ const PrivateAccessor getPrivateAccessor() const { return PrivateAccessor(this); }
private:
- friend PrivateAccessorForId;
+ friend PrivateAccessor;
friend class sp<BpBinder>;
+ static sp<BpBinder> create(int32_t handle);
+ static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address);
+
struct BinderHandle {
int32_t handle;
};
struct RpcHandle {
sp<RpcSession> session;
- RpcAddress address;
+ uint64_t address;
};
using Handle = std::variant<BinderHandle, RpcHandle>;
int32_t binderHandle() const;
- const RpcAddress& rpcAddress() const;
+ uint64_t rpcAddress() const;
const sp<RpcSession>& rpcSession() const;
explicit BpBinder(Handle&& handle);
@@ -194,6 +197,7 @@
static uint32_t sBinderProxyCountHighWatermark;
static uint32_t sBinderProxyCountLowWatermark;
static bool sBinderProxyThrottleCreate;
+ static std::unordered_map<int32_t,uint32_t> sLastLimitCallbackMap;
};
} // namespace android
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 20a9f36..065e6e3 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -53,6 +53,13 @@
// Provide information about the state of a frozen process
static status_t getProcessFreezeInfo(pid_t pid, bool *sync_received,
bool *async_received);
+
+ // TODO: Remove the above legacy duplicated function in next version
+#ifndef __ANDROID_VNDK__
+ static status_t getProcessFreezeInfo(pid_t pid, uint32_t *sync_received,
+ uint32_t *async_received);
+#endif
+
sp<ProcessState> process();
status_t clearLastError();
diff --git a/libs/binder/include/binder/RpcAddress.h b/libs/binder/include/binder/RpcAddress.h
deleted file mode 100644
index e428908..0000000
--- a/libs/binder/include/binder/RpcAddress.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-#pragma once
-
-#include <memory>
-
-#include <utils/Errors.h>
-
-// WARNING: This is a feature which is still in development, and it is subject
-// to radical change. Any production use of this may subject your code to any
-// number of problems.
-
-namespace android {
-
-class Parcel;
-struct RpcWireAddress;
-
-/**
- * This class represents an identifier across an RPC boundary.
- */
-class RpcAddress {
-public:
- /**
- * The zero address is used for special RPC transactions, but it might also
- * be used in conjunction with readFromParcel.
- */
- static RpcAddress zero();
-
- bool isZero() const;
-
- /**
- * Create a new random address.
- */
- static RpcAddress random(bool forServer);
-
- /**
- * Whether this address was created with 'bool forServer' true
- */
- bool isForServer() const;
-
- /**
- * Whether this address is one that could be created with this version of
- * libbinder.
- */
- bool isRecognizedType() const;
-
- /**
- * Creates a new address as a copy of an embedded object.
- */
- static RpcAddress fromRawEmbedded(const RpcWireAddress* raw);
- const RpcWireAddress& viewRawEmbedded() const;
-
- bool operator<(const RpcAddress& rhs) const;
- std::string toString() const;
-
- status_t writeToParcel(Parcel* parcel) const;
- status_t readFromParcel(const Parcel& parcel);
-
- ~RpcAddress();
-
-private:
- RpcAddress();
-
- std::shared_ptr<RpcWireAddress> mRawAddr;
-};
-
-} // namespace android
diff --git a/libs/binder/include/binder/RpcCertificateFormat.h b/libs/binder/include/binder/RpcCertificateFormat.h
new file mode 100644
index 0000000..bc9d814
--- /dev/null
+++ b/libs/binder/include/binder/RpcCertificateFormat.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+// Formats for serializing TLS certificate.
+
+#pragma once
+
+#include <string>
+
+namespace android {
+
+enum class RpcCertificateFormat {
+ PEM,
+ DER,
+};
+
+static inline std::string PrintToString(RpcCertificateFormat format) {
+ switch (format) {
+ case RpcCertificateFormat::PEM:
+ return "PEM";
+ case RpcCertificateFormat::DER:
+ return "DER";
+ default:
+ return "<unknown>";
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/include/binder/RpcCertificateVerifier.h
similarity index 60%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/include/binder/RpcCertificateVerifier.h
index 7932d0f..97af31c 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/include/binder/RpcCertificateVerifier.h
@@ -16,11 +16,17 @@
#pragma once
-extern "C" {
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
-struct AIBinder;
+namespace android {
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
+// An interface with a function that verifies a peer certificate. It is a wrapper over the custom
+// verify function (see SSL_CTX_set_custom_verify).
+class RpcCertificateVerifier {
+public:
+ virtual ~RpcCertificateVerifier() = default;
+ virtual status_t verify(const X509* peerCert, uint8_t* outAlert) = 0;
+};
-}
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index d0e4e27..fb2cf23 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -17,7 +17,6 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
-#include <binder/RpcAddress.h>
#include <binder/RpcSession.h>
#include <binder/RpcTransport.h>
#include <utils/Errors.h>
@@ -136,13 +135,7 @@
/**
* See RpcTransportCtx::getCertificate
*/
- std::string getCertificate(CertificateFormat);
-
- /**
- * See RpcTransportCtx::addTrustedPeerCertificate.
- * Thread-safe. This is only possible before the server is join()-ing.
- */
- status_t addTrustedPeerCertificate(CertificateFormat, std::string_view cert);
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat);
/**
* Runs join() in a background thread. Immediately returns.
@@ -201,7 +194,7 @@
std::map<std::thread::id, std::thread> mConnectingThreads;
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
- std::map<RpcAddress, sp<RpcSession>> mSessions;
+ std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
std::condition_variable mShutdownCv;
};
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index d92af0a..6a29c05 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -17,7 +17,6 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
-#include <binder/RpcAddress.h>
#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -54,12 +53,10 @@
// Create an RpcSession with default configuration (raw sockets).
static sp<RpcSession> make();
- // Create an RpcSession with the given configuration. |serverCertificateFormat| and
+ // Create an RpcSession with the given configuration. |serverRpcCertificateFormat| and
// |serverCertificate| must have values or be nullopt simultaneously. If they have values, set
// server certificate.
- static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
- std::optional<CertificateFormat> serverCertificateFormat,
- std::optional<std::string> serverCertificate);
+ static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
/**
* Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -134,7 +131,7 @@
/**
* See RpcTransportCtx::getCertificate
*/
- std::string getCertificate(CertificateFormat);
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat);
/**
* Shuts down the service.
@@ -154,7 +151,13 @@
[[nodiscard]] status_t transact(const sp<IBinder>& binder, uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
- [[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
+
+ /**
+ * Generally, you should not call this, unless you are testing error
+ * conditions, as this is called automatically by BpBinders when they are
+ * deleted (this is also why a raw pointer is used here)
+ */
+ [[nodiscard]] status_t sendDecStrong(const BpBinder* binder);
~RpcSession();
@@ -173,6 +176,8 @@
friend RpcState;
explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
+ [[nodiscard]] status_t sendDecStrong(uint64_t address);
+
class EventListener : public virtual RefBase {
public:
virtual void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) = 0;
@@ -183,12 +188,12 @@
public:
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
- void waitForShutdown(std::unique_lock<std::mutex>& lock);
+ void waitForShutdown(std::unique_lock<std::mutex>& lock, const sp<RpcSession>& session);
private:
std::condition_variable mCv;
- volatile bool mShutdown = false;
};
+ friend WaitForShutdownListener;
struct RpcConnection : public RefBase {
std::unique_ptr<RpcTransport> rpcTransport;
@@ -222,19 +227,21 @@
static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
[[nodiscard]] status_t setupClient(
- const std::function<status_t(const RpcAddress& sessionId, bool incoming)>&
+ const std::function<status_t(const std::vector<uint8_t>& sessionId, bool incoming)>&
connectAndInit);
[[nodiscard]] status_t setupSocketClient(const RpcSocketAddress& address);
[[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
- const RpcAddress& sessionId, bool incoming);
- [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd, const RpcAddress& sessionId,
+ const std::vector<uint8_t>& sessionId,
+ bool incoming);
+ [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd,
+ const std::vector<uint8_t>& sessionId,
bool incoming);
[[nodiscard]] status_t addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport);
[[nodiscard]] status_t addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport,
bool init);
[[nodiscard]] bool setForServer(const wp<RpcServer>& server,
const wp<RpcSession::EventListener>& eventListener,
- const RpcAddress& sessionId);
+ const std::vector<uint8_t>& sessionId);
sp<RpcConnection> assignIncomingConnectionToThisThread(
std::unique_ptr<RpcTransport> rpcTransport);
[[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
@@ -291,7 +298,7 @@
sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
- std::optional<RpcAddress> mId;
+ std::vector<uint8_t> mId;
std::unique_ptr<FdTrigger> mShutdownTrigger;
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index 8d08b34..1c0bb18 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -25,15 +25,12 @@
#include <android-base/unique_fd.h>
#include <utils/Errors.h>
+#include <binder/RpcCertificateFormat.h>
+
namespace android {
class FdTrigger;
-enum class CertificateFormat {
- PEM,
- // TODO(b/195166979): support other formats, e.g. DER
-};
-
// Represents a socket connection.
// No thread-safety is guaranteed for these APIs.
class RpcTransport {
@@ -76,19 +73,8 @@
// Implementation details:
// - For raw sockets, this always returns empty string.
// - For TLS, this returns the certificate. See RpcTransportTls for details.
- [[nodiscard]] virtual std::string getCertificate(CertificateFormat format) const = 0;
-
- // Add a trusted peer certificate. Peers presenting this certificate are accepted.
- //
- // Caller must ensure that newTransport() are called after all trusted peer certificates
- // are added. Otherwise, RpcTransport-s created before may not trust peer certificates
- // added later.
- //
- // Implementation details:
- // - For raw sockets, this always returns OK.
- // - For TLS, this adds trusted peer certificate. See RpcTransportTls for details.
- [[nodiscard]] virtual status_t addTrustedPeerCertificate(CertificateFormat format,
- std::string_view cert) = 0;
+ [[nodiscard]] virtual std::vector<uint8_t> getCertificate(
+ RpcCertificateFormat format) const = 0;
protected:
RpcTransportCtx() = default;
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
new file mode 100644
index 0000000..08f5eed
--- /dev/null
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+extern "C" {
+
+struct AIBinder;
+
+// Starts an RPC server on a given port and a given root IBinder object.
+// This function sets up the server and joins before returning.
+bool RunRpcServer(AIBinder* service, unsigned int port);
+
+// Starts an RPC server on a given port and a given root IBinder object.
+// This function sets up the server, calls readyCallback with a given param, and
+// then joins before returning.
+bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
+ void* param);
+
+AIBinder* RpcClient(unsigned int cid, unsigned int port);
+
+// Connect to an RPC server with preconnected file descriptors.
+//
+// requestFd should connect to the server and return a valid file descriptor, or
+// -1 if connection fails.
+//
+// param will be passed to requestFd. Callers can use param to pass contexts to
+// the requestFd function.
+AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param);
+
+}
diff --git a/libs/binder/include_tls/binder/RpcCertificateUtils.h b/libs/binder/include_tls/binder/RpcCertificateUtils.h
new file mode 100644
index 0000000..8d07835
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcCertificateUtils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+// Utilities for serializing and deserializing X509 certificates.
+
+#pragma once
+
+#include <vector>
+
+#include <openssl/ssl.h>
+
+#include <binder/RpcCertificateFormat.h>
+
+namespace android {
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
+ RpcCertificateFormat format);
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format);
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h
index 531aaa9..f26a3e9 100644
--- a/libs/binder/include_tls/binder/RpcTransportTls.h
+++ b/libs/binder/include_tls/binder/RpcTransportTls.h
@@ -18,6 +18,7 @@
#pragma once
+#include <binder/RpcCertificateVerifier.h>
#include <binder/RpcTransport.h>
namespace android {
@@ -25,14 +26,17 @@
// RpcTransportCtxFactory with TLS enabled with self-signed certificate.
class RpcTransportCtxFactoryTls : public RpcTransportCtxFactory {
public:
- static std::unique_ptr<RpcTransportCtxFactory> make();
+ static std::unique_ptr<RpcTransportCtxFactory> make(std::shared_ptr<RpcCertificateVerifier>);
std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
const char* toCString() const override;
private:
- RpcTransportCtxFactoryTls() = default;
+ RpcTransportCtxFactoryTls(std::shared_ptr<RpcCertificateVerifier> verifier)
+ : mCertVerifier(std::move(verifier)){};
+
+ std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
};
} // namespace android
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index bcb13ae..cad55fb 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -15,6 +15,7 @@
*/
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <android/binder_libbinder.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
@@ -24,10 +25,12 @@
using android::RpcSession;
using android::status_t;
using android::statusToString;
+using android::base::unique_fd;
extern "C" {
-bool RunRpcServer(AIBinder* service, unsigned int port) {
+bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
+ void* param) {
auto server = RpcServer::make();
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
if (status_t status = server->setupVsockServer(port); status != OK) {
@@ -36,6 +39,8 @@
return false;
}
server->setRootObject(AIBinder_toPlatformBinder(service));
+
+ if (readyCallback) readyCallback(param);
server->join();
// Shutdown any open sessions since server failed.
@@ -43,6 +48,10 @@
return true;
}
+bool RunRpcServer(AIBinder* service, unsigned int port) {
+ return RunRpcServerCallback(service, port, nullptr, nullptr);
+}
+
AIBinder* RpcClient(unsigned int cid, unsigned int port) {
auto session = RpcSession::make();
if (status_t status = session->setupVsockClient(cid, port); status != OK) {
@@ -52,4 +61,14 @@
}
return AIBinder_fromPlatformBinder(session->getRootObject());
}
+
+AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
+ auto session = RpcSession::make();
+ auto request = [=] { return unique_fd{requestFd(param)}; };
+ if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock client. error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ return AIBinder_fromPlatformBinder(session->getRootObject());
+}
}
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
index 3921a4d..e856569 100644
--- a/libs/binder/libbinder_rpc_unstable.map.txt
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -1,7 +1,9 @@
LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only
global:
RunRpcServer;
+ RunRpcServerCallback;
RpcClient;
+ RpcPreconnectedClient;
local:
*;
};
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index b03e24c..9c04e58 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -117,6 +117,9 @@
"30",
],
},
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
tidy: true,
tidy_flags: [
// Only check our headers
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index c82df83..b881c2c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -227,11 +227,11 @@
* must have a separate way of determining the binder you are talking to is the right type. Must
* be called before any instance of the class is created.
*
- * Available since API level 32.
+ * Available since API level 33.
*
* \param clazz class to disable interface header on.
*/
-void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) __INTRODUCED_IN(32);
+void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) __INTRODUCED_IN(33);
/**
* Creates a new binder object of the appropriate class.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 527b151..a2f5c93 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1163,6 +1163,41 @@
* \return A parcel which is not related to any IBinder objects.
*/
AParcel* AParcel_create() __INTRODUCED_IN(31);
+
+/**
+ * Marshals the raw bytes of the Parcel to a buffer.
+ *
+ * The parcel must not contain any binders or file descriptors.
+ *
+ * The data you retrieve here must not be placed in any kind of persistent storage. (on local disk,
+ * across a network, etc). For that, you should use standard serialization or another kind of
+ * general serialization mechanism. The Parcel marshalled representation is highly optimized for
+ * local IPC, and as such does not attempt to maintain compatibility with data created in different
+ * versions of the platform.
+ *
+ * \param parcel The parcel of which to get the data.
+ * \param buffer The buffer to copy the raw bytes to.
+ * \param start The start position in the buffer to copy from.
+ * \param len The size of the data to copy, buffer size must be larger or equal to this.
+ *
+ * \return STATUS_OK on success, STATUS_INVALID_OPERATION if parcel contains binders or file
+ * descriptors. STATUS_BAD_VALUE if the buffer size is less than parcel size.
+ */
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len)
+ __INTRODUCED_IN(33);
+
+/**
+ * Set the data in the parcel to the raw bytes from the buffer.
+ *
+ * \param parcel The parcel to set data.
+ * \param buffer The data buffer to set.
+ * \param len The size of the data to set.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len)
+ __INTRODUCED_IN(33);
+
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 1975bdc..ac892db 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -141,9 +141,11 @@
AParcel_reset;
};
-LIBBINDER_NDK32 { # introduced=32
+LIBBINDER_NDK33 { # introduced=33
global:
AIBinder_Class_disableInterfaceTokenHeader;
+ AParcel_marshal;
+ AParcel_unmarshal;
};
LIBBINDER_NDK_PLATFORM {
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index b2f21c7..c320e8d 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -673,4 +673,32 @@
return new AParcel(nullptr);
}
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len) {
+ if (parcel->get()->objectsCount()) {
+ return STATUS_INVALID_OPERATION;
+ }
+ int32_t dataSize = AParcel_getDataSize(parcel);
+ if (len > static_cast<size_t>(dataSize) || start > static_cast<size_t>(dataSize) - len) {
+ return STATUS_BAD_VALUE;
+ }
+ const uint8_t* internalBuffer = parcel->get()->data();
+ memcpy(buffer, internalBuffer + start, len);
+ return STATUS_OK;
+}
+
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len) {
+ status_t status = parcel->get()->setDataSize(len);
+ if (status != ::android::OK) {
+ return PruneStatusT(status);
+ }
+ parcel->get()->setDataPosition(0);
+
+ void* raw = parcel->get()->writeInplace(len);
+ if (raw == nullptr) {
+ return STATUS_NO_MEMORY;
+ }
+ memcpy(raw, buffer, len);
+ return STATUS_OK;
+}
+
// @END
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index fe2da18..d9d7caf 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -109,7 +109,7 @@
// TODO(b/184872979): remove once the Rust API is created.
rust_bindgen {
name: "libbinder_rpc_unstable_bindgen",
- wrapper_src: "src/binder_rpc_unstable.hpp",
+ wrapper_src: ":libbinder_rpc_unstable_header",
crate_name: "binder_rpc_unstable_bindgen",
source_stem: "bindings",
shared_libs: [
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index cb330a6..7e8e3a5 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -112,8 +112,7 @@
FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
-pub use native::add_service;
-pub use native::Binder;
+pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder};
pub use parcel::Parcel;
pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
@@ -129,7 +128,10 @@
/// The public API usable outside AIDL-generated interface crates.
pub mod public_api {
pub use super::parcel::ParcelFileDescriptor;
- pub use super::{add_service, get_interface, wait_for_interface};
+ pub use super::{
+ add_service, force_lazy_services_persist, get_interface, register_lazy_service,
+ wait_for_interface,
+ };
pub use super::{
BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index a0dfeec..e7c3396 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode};
+use crate::binder::{
+ AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode,
+};
use crate::error::{status_result, status_t, Result, StatusCode};
use crate::parcel::{Parcel, Serialize};
use crate::proxy::SpIBinder;
@@ -321,7 +323,12 @@
/// contains a `T` pointer in its user data. fd should be a non-owned file
/// descriptor, and args must be an array of null-terminated string
/// poiinters with length num_args.
- unsafe extern "C" fn on_dump(binder: *mut sys::AIBinder, fd: i32, args: *mut *const c_char, num_args: u32) -> status_t {
+ unsafe extern "C" fn on_dump(
+ binder: *mut sys::AIBinder,
+ fd: i32,
+ args: *mut *const c_char,
+ num_args: u32,
+ ) -> status_t {
if fd < 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
}
@@ -447,6 +454,41 @@
status_result(status)
}
+/// Register a dynamic service via the LazyServiceRegistrar.
+///
+/// Registers the given binder object with the given identifier. If successful,
+/// this service can then be retrieved using that identifier. The service process
+/// will be shut down once all registered services are no longer in use.
+///
+/// If any service in the process is registered as lazy, all should be, otherwise
+/// the process may be shut down while a service is in use.
+pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
+ let instance = CString::new(identifier).unwrap();
+ let status = unsafe {
+ // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
+ // string pointers. Caller retains ownership of both
+ // pointers. `AServiceManager_registerLazyService` creates a new strong reference
+ // and copies the string, so both pointers need only be valid until the
+ // call returns.
+
+ sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
+ };
+ status_result(status)
+}
+
+/// Prevent a process which registers lazy services from being shut down even when none
+/// of the services is in use.
+///
+/// If persist is true then shut down will be blocked until this function is called again with
+/// persist false. If this is to be the initial state, call this function before calling
+/// register_lazy_service.
+pub fn force_lazy_services_persist(persist: bool) {
+ unsafe {
+ // Safety: No borrowing or transfer of ownership occurs here.
+ sys::AServiceManager_forceLazyServicesPersist(persist)
+ }
+}
+
/// Tests often create a base BBinder instance; so allowing the unit
/// type to be remotable translates nicely to Binder::new(()).
impl Remotable for () {
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 13ea827..1968058 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -120,9 +120,12 @@
host_supported: true,
unstable: true,
srcs: [
+ "BinderRpcTestClientInfo.aidl",
+ "BinderRpcTestServerInfo.aidl",
"IBinderRpcCallback.aidl",
"IBinderRpcSession.aidl",
"IBinderRpcTest.aidl",
+ "ParcelableCertificateData.aidl",
],
backend: {
java: {
@@ -150,6 +153,7 @@
srcs: [
"binderRpcTest.cpp",
+ "RpcCertificateVerifierSimple.cpp",
],
shared_libs: [
"libbinder",
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/tests/BinderRpcTestClientInfo.aidl
similarity index 78%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/tests/BinderRpcTestClientInfo.aidl
index 7932d0f..b4baebc 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/tests/BinderRpcTestClientInfo.aidl
@@ -14,13 +14,8 @@
* limitations under the License.
*/
-#pragma once
+import ParcelableCertificateData;
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+parcelable BinderRpcTestClientInfo {
+ ParcelableCertificateData[] certs;
}
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/tests/BinderRpcTestServerInfo.aidl
similarity index 78%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/tests/BinderRpcTestServerInfo.aidl
index 7932d0f..00dc0bc 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/tests/BinderRpcTestServerInfo.aidl
@@ -14,13 +14,9 @@
* limitations under the License.
*/
-#pragma once
+import ParcelableCertificateData;
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+parcelable BinderRpcTestServerInfo {
+ long port;
+ ParcelableCertificateData cert;
}
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/tests/ParcelableCertificateData.aidl
similarity index 78%
rename from libs/binder/rust/src/binder_rpc_unstable.hpp
rename to libs/binder/tests/ParcelableCertificateData.aidl
index 7932d0f..38c382e 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/tests/ParcelableCertificateData.aidl
@@ -14,13 +14,6 @@
* limitations under the License.
*/
-#pragma once
-
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+parcelable ParcelableCertificateData {
+ byte[] data;
}
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.cpp b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
new file mode 100644
index 0000000..4694d1b
--- /dev/null
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+#define LOG_TAG "RpcCertificateVerifierSimple"
+#include <log/log.h>
+
+#include <binder/RpcCertificateUtils.h>
+
+#include "RpcCertificateVerifierSimple.h"
+
+namespace android {
+
+status_t RpcCertificateVerifierSimple::verify(const X509* peerCert, uint8_t* outAlert) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (const auto& trustedCert : mTrustedPeerCertificates) {
+ if (0 == X509_cmp(trustedCert.get(), peerCert)) {
+ return OK;
+ }
+ }
+ *outAlert = SSL_AD_CERTIFICATE_UNKNOWN;
+ return PERMISSION_DENIED;
+}
+
+status_t RpcCertificateVerifierSimple::addTrustedPeerCertificate(RpcCertificateFormat format,
+ const std::vector<uint8_t>& cert) {
+ bssl::UniquePtr<X509> x509 = deserializeCertificate(cert, format);
+ if (x509 == nullptr) {
+ ALOGE("Certificate is not in the proper format %s", PrintToString(format).c_str());
+ return BAD_VALUE;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTrustedPeerCertificates.push_back(std::move(x509));
+ return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.h b/libs/binder/tests/RpcCertificateVerifierSimple.h
new file mode 100644
index 0000000..1f2e531
--- /dev/null
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <string_view>
+#include <vector>
+
+#include <openssl/ssl.h>
+
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcCertificateVerifier.h>
+
+namespace android {
+
+// A simple certificate verifier for testing.
+// Keep a list of leaf certificates as trusted. No certificate chain support.
+//
+// All APIs are thread-safe. However, if verify() and addTrustedPeerCertificate() are called
+// simultaneously in different threads, it is not deterministic whether verify() will use the
+// certificate being added.
+class RpcCertificateVerifierSimple : public RpcCertificateVerifier {
+public:
+ status_t verify(const X509*, uint8_t*) override;
+
+ // Add a trusted peer certificate. Peers presenting this certificate are accepted.
+ //
+ // Caller must ensure that RpcTransportCtx::newTransport() are called after all trusted peer
+ // certificates are added. Otherwise, RpcTransport-s created before may not trust peer
+ // certificates added later.
+ [[nodiscard]] status_t addTrustedPeerCertificate(RpcCertificateFormat format,
+ const std::vector<uint8_t>& cert);
+
+private:
+ std::mutex mMutex; // for below
+ std::vector<bssl::UniquePtr<X509>> mTrustedPeerCertificates;
+};
+
+} // namespace android
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index eea7d8c..639876f 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -465,31 +465,30 @@
TEST_F(BinderLibTest, Freeze) {
Parcel data, reply, replypid;
- std::ifstream freezer_file("/sys/fs/cgroup/freezer/cgroup.freeze");
+ std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze");
- //Pass test on devices where the freezer is not supported
+ // Pass test on devices where the cgroup v2 freezer is not supported
if (freezer_file.fail()) {
GTEST_SKIP();
return;
}
- std::string freezer_enabled;
- std::getline(freezer_file, freezer_enabled);
-
- //Pass test on devices where the freezer is disabled
- if (freezer_enabled != "1") {
- GTEST_SKIP();
- return;
- }
-
EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid), StatusEq(NO_ERROR));
int32_t pid = replypid.readInt32();
for (int i = 0; i < 10; i++) {
EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
}
- EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
- EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
- EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 1, 1000));
+
+ // Pass test on devices where BINDER_FREEZE ioctl is not supported
+ int ret = IPCThreadState::self()->freeze(pid, false, 0);
+ if (ret != 0) {
+ GTEST_SKIP();
+ return;
+ }
+
+ EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0));
+ EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0));
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, true, 1000));
EXPECT_EQ(FAILED_TRANSACTION, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
bool sync_received, async_received;
@@ -500,6 +499,14 @@
EXPECT_EQ(sync_received, 1);
EXPECT_EQ(async_received, 0);
+ uint32_t sync_received2, async_received2;
+
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->getProcessFreezeInfo(pid, &sync_received2,
+ &async_received2));
+
+ EXPECT_EQ(sync_received2, 1);
+ EXPECT_EQ(async_received2, 0);
+
EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 0, 0));
EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
}
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index e430c28..55aa57b 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -211,10 +211,9 @@
for (size_t tries = 0; tries < 5; tries++) {
usleep(10000);
status = gSession->setupUnixDomainClient(addr.c_str());
- if (status == OK) goto success;
+ if (status == OK) break;
}
- LOG(FATAL) << "Could not connect: " << statusToString(status).c_str();
-success:
+ CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status).c_str();
::benchmark::RunSpecifiedBenchmarks();
return 0;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 7c405d3..6bcf102 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <BinderRpcTestClientInfo.h>
+#include <BinderRpcTestServerInfo.h>
#include <BnBinderRpcCallback.h>
#include <BnBinderRpcSession.h>
#include <BnBinderRpcTest.h>
@@ -40,14 +42,21 @@
#include <thread>
#include <type_traits>
+#include <poll.h>
#include <sys/prctl.h>
#include <unistd.h>
+#include "../FdTrigger.h"
#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
+#include "RpcCertificateVerifierSimple.h"
using namespace std::chrono_literals;
+using namespace std::placeholders;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
namespace android {
@@ -61,12 +70,17 @@
return {RpcSecurity::RAW, RpcSecurity::TLS};
}
-static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(RpcSecurity rpcSecurity) {
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
+ RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr) {
switch (rpcSecurity) {
case RpcSecurity::RAW:
return RpcTransportCtxFactoryRaw::make();
- case RpcSecurity::TLS:
- return RpcTransportCtxFactoryTls::make();
+ case RpcSecurity::TLS: {
+ if (verifier == nullptr) {
+ verifier = std::make_shared<RpcCertificateVerifierSimple>();
+ }
+ return RpcTransportCtxFactoryTls::make(std::move(verifier));
+ }
default:
LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
}
@@ -304,14 +318,17 @@
class Process {
public:
Process(Process&&) = default;
- Process(const std::function<void(android::base::borrowed_fd /* writeEnd */)>& f) {
- android::base::unique_fd writeEnd;
- CHECK(android::base::Pipe(&mReadEnd, &writeEnd)) << strerror(errno);
+ Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
+ android::base::borrowed_fd /* readEnd */)>& f) {
+ android::base::unique_fd childWriteEnd;
+ android::base::unique_fd childReadEnd;
+ CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
+ CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
if (0 == (mPid = fork())) {
// racey: assume parent doesn't crash before this is set
prctl(PR_SET_PDEATHSIG, SIGHUP);
- f(writeEnd);
+ f(childWriteEnd, childReadEnd);
exit(0);
}
@@ -322,16 +339,20 @@
}
}
android::base::borrowed_fd readEnd() { return mReadEnd; }
+ android::base::borrowed_fd writeEnd() { return mWriteEnd; }
private:
pid_t mPid = 0;
android::base::unique_fd mReadEnd;
+ android::base::unique_fd mWriteEnd;
};
static std::string allocateSocketAddress() {
static size_t id = 0;
std::string temp = getenv("TMPDIR") ?: "/tmp";
- return temp + "/binderRpcTest_" + std::to_string(id++);
+ auto ret = temp + "/binderRpcTest_" + std::to_string(id++);
+ unlink(ret.c_str());
+ return ret;
};
static unsigned int allocateVsockPort() {
@@ -434,16 +455,17 @@
}
}
-static base::unique_fd connectToUds(const char* addrStr) {
- UnixSocketAddress addr(addrStr);
+static base::unique_fd connectTo(const RpcSocketAddress& addr) {
base::unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
int savedErrno = errno;
- CHECK(serverFd.ok()) << "Could not create socket " << addrStr << ": " << strerror(savedErrno);
+ CHECK(serverFd.ok()) << "Could not create socket " << addr.toString() << ": "
+ << strerror(savedErrno);
if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
int savedErrno = errno;
- LOG(FATAL) << "Could not connect to socket " << addrStr << ": " << strerror(savedErrno);
+ LOG(FATAL) << "Could not connect to socket " << addr.toString() << ": "
+ << strerror(savedErrno);
}
return serverFd;
}
@@ -461,6 +483,37 @@
return PrintToString(type) + "_" + newFactory(security)->toCString();
}
+ static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
+ uint64_t length = str.length();
+ CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
+ CHECK(android::base::WriteFully(fd, str.data(), str.length()));
+ }
+
+ static inline std::string readString(android::base::borrowed_fd fd) {
+ uint64_t length;
+ CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
+ std::string ret(length, '\0');
+ CHECK(android::base::ReadFully(fd, ret.data(), length));
+ return ret;
+ }
+
+ static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
+ Parcel parcel;
+ CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
+ writeString(fd,
+ std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
+ }
+
+ template <typename T>
+ static inline T readFromFd(android::base::borrowed_fd fd) {
+ std::string data = readString(fd);
+ Parcel parcel;
+ CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+ T object;
+ CHECK_EQ(OK, object.readFromParcel(&parcel));
+ return object;
+ }
+
// This creates a new process serving an interface on a certain number of
// threads.
ProcessSession createRpcTestSocketServerProcess(
@@ -472,11 +525,12 @@
unsigned int vsockPort = allocateVsockPort();
std::string addr = allocateSocketAddress();
- unlink(addr.c_str());
auto ret = ProcessSession{
- .host = Process([&](android::base::borrowed_fd writeEnd) {
- sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity));
+ .host = Process([&](android::base::borrowed_fd writeEnd,
+ android::base::borrowed_fd readEnd) {
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
server->setMaxThreads(options.numThreads);
@@ -501,7 +555,20 @@
LOG_ALWAYS_FATAL("Unknown socket type");
}
- CHECK(android::base::WriteFully(writeEnd, &outPort, sizeof(outPort)));
+ BinderRpcTestServerInfo serverInfo;
+ serverInfo.port = static_cast<int64_t>(outPort);
+ serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
+ writeToFd(writeEnd, serverInfo);
+ auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
+
+ if (rpcSecurity == RpcSecurity::TLS) {
+ for (const auto& clientCert : clientInfo.certs) {
+ CHECK_EQ(OK,
+ certVerifier
+ ->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ clientCert.data));
+ }
+ }
configure(server);
@@ -512,44 +579,56 @@
}),
};
- // always read socket, so that we have waited for the server to start
- unsigned int outPort = 0;
- CHECK(android::base::ReadFully(ret.host.readEnd(), &outPort, sizeof(outPort)));
+ std::vector<sp<RpcSession>> sessions;
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ for (size_t i = 0; i < options.numSessions; i++) {
+ sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
+ }
+
+ auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
+ BinderRpcTestClientInfo clientInfo;
+ for (const auto& session : sessions) {
+ auto& parcelableCert = clientInfo.certs.emplace_back();
+ parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+ }
+ writeToFd(ret.host.writeEnd(), clientInfo);
+
+ CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
if (socketType == SocketType::INET) {
- CHECK_NE(0, outPort);
+ CHECK_NE(0, serverInfo.port);
+ }
+
+ if (rpcSecurity == RpcSecurity::TLS) {
+ const auto& serverCert = serverInfo.cert.data;
+ CHECK_EQ(OK,
+ certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ serverCert));
}
status_t status;
- for (size_t i = 0; i < options.numSessions; i++) {
- sp<RpcSession> session =
- RpcSession::make(newFactory(rpcSecurity), std::nullopt, std::nullopt);
+ for (const auto& session : sessions) {
session->setMaxThreads(options.numIncomingConnections);
switch (socketType) {
case SocketType::PRECONNECTED:
status = session->setupPreconnectedClient({}, [=]() {
- return connectToUds(addr.c_str());
+ return connectTo(UnixSocketAddress(addr.c_str()));
});
- if (status == OK) goto success;
break;
case SocketType::UNIX:
status = session->setupUnixDomainClient(addr.c_str());
- if (status == OK) goto success;
break;
case SocketType::VSOCK:
status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
- if (status == OK) goto success;
break;
case SocketType::INET:
- status = session->setupInetClient("127.0.0.1", outPort);
- if (status == OK) goto success;
+ status = session->setupInetClient("127.0.0.1", serverInfo.port);
break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
- LOG_ALWAYS_FATAL("Could not connect %s", statusToString(status).c_str());
- success:
+ CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
ret.sessions.push_back({session, session->getRootObject()});
}
return ret;
@@ -1208,16 +1287,17 @@
}
server->start();
- sp<RpcSession> session =
- RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+ sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
while (!server->shutdown()) usleep(10000);
ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
return status == OK;
}
-static std::vector<SocketType> testSocketTypes() {
- std::vector<SocketType> ret = {SocketType::PRECONNECTED, SocketType::UNIX, SocketType::INET};
+static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
+ std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+
+ if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
static bool hasVsockLoopback = testSupportVsockLoopback();
@@ -1286,7 +1366,6 @@
TEST_P(BinderRpcSimple, Shutdown) {
auto addr = allocateSocketAddress();
- unlink(addr.c_str());
auto server = RpcServer::make(newFactory(GetParam()));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
@@ -1351,6 +1430,415 @@
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
BinderRpcSimple::PrintTestParam);
+class RpcTransportTest
+ : public ::testing::TestWithParam<
+ std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>> {
+public:
+ using ConnectToServer = std::function<base::unique_fd()>;
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [socketType, rpcSecurity, certificateFormat] = info.param;
+ auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
+ if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
+ return ret;
+ }
+ static std::vector<ParamType> getRpcTranportTestParams() {
+ std::vector<RpcTransportTest::ParamType> ret;
+ for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
+ for (auto rpcSecurity : RpcSecurityValues()) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW: {
+ ret.emplace_back(socketType, rpcSecurity, std::nullopt);
+ } break;
+ case RpcSecurity::TLS: {
+ ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
+ ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
+ } break;
+ }
+ }
+ }
+ return ret;
+ }
+ void TearDown() override {
+ for (auto& server : mServers) server->shutdownAndWait();
+ }
+
+ // A server that handles client socket connections.
+ class Server {
+ public:
+ explicit Server() {}
+ Server(Server&&) = default;
+ ~Server() { shutdownAndWait(); }
+ [[nodiscard]] AssertionResult setUp() {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+ rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ switch (socketType) {
+ case SocketType::PRECONNECTED: {
+ return AssertionFailure() << "Not supported by this test";
+ } break;
+ case SocketType::UNIX: {
+ auto addr = allocateSocketAddress();
+ auto status = rpcServer->setupUnixDomainServer(addr.c_str());
+ if (status != OK) {
+ return AssertionFailure()
+ << "setupUnixDomainServer: " << statusToString(status);
+ }
+ mConnectToServer = [addr] {
+ return connectTo(UnixSocketAddress(addr.c_str()));
+ };
+ } break;
+ case SocketType::VSOCK: {
+ auto port = allocateVsockPort();
+ auto status = rpcServer->setupVsockServer(port);
+ if (status != OK) {
+ return AssertionFailure() << "setupVsockServer: " << statusToString(status);
+ }
+ mConnectToServer = [port] {
+ return connectTo(VsockSocketAddress(VMADDR_CID_LOCAL, port));
+ };
+ } break;
+ case SocketType::INET: {
+ unsigned int port;
+ auto status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port);
+ if (status != OK) {
+ return AssertionFailure() << "setupInetServer: " << statusToString(status);
+ }
+ mConnectToServer = [port] {
+ const char* addr = kLocalInetAddress;
+ auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
+ if (aiStart == nullptr) return base::unique_fd{};
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ auto fd = connectTo(
+ InetSocketAddress(ai->ai_addr, ai->ai_addrlen, addr, port));
+ if (fd.ok()) return fd;
+ }
+ ALOGE("None of the socket address resolved for %s:%u can be connected",
+ addr, port);
+ return base::unique_fd{};
+ };
+ }
+ }
+ mFd = rpcServer->releaseServer();
+ if (!mFd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
+ mCtx = newFactory(rpcSecurity, mCertVerifier)->newServerCtx();
+ if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
+ mSetup = true;
+ return AssertionSuccess();
+ }
+ RpcTransportCtx* getCtx() const { return mCtx.get(); }
+ std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+ return mCertVerifier;
+ }
+ ConnectToServer getConnectToServerFn() { return mConnectToServer; }
+ void start() {
+ LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+ mThread = std::make_unique<std::thread>(&Server::run, this);
+ }
+ void run() {
+ LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+
+ std::vector<std::thread> threads;
+ while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) {
+ base::unique_fd acceptedFd(
+ TEMP_FAILURE_RETRY(accept4(mFd.get(), nullptr, nullptr /*length*/,
+ SOCK_CLOEXEC | SOCK_NONBLOCK)));
+ threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd));
+ }
+
+ for (auto& thread : threads) thread.join();
+ }
+ void handleOne(android::base::unique_fd acceptedFd) {
+ ASSERT_TRUE(acceptedFd.ok());
+ auto serverTransport = mCtx->newTransport(std::move(acceptedFd), mFdTrigger.get());
+ if (serverTransport == nullptr) return; // handshake failed
+ ASSERT_TRUE(mPostConnect(serverTransport.get(), mFdTrigger.get()));
+ }
+ void shutdownAndWait() {
+ shutdown();
+ join();
+ }
+ void shutdown() { mFdTrigger->trigger(); }
+
+ void setPostConnect(
+ std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> fn) {
+ mPostConnect = std::move(fn);
+ }
+
+ private:
+ std::unique_ptr<std::thread> mThread;
+ ConnectToServer mConnectToServer;
+ std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+ base::unique_fd mFd;
+ std::unique_ptr<RpcTransportCtx> mCtx;
+ std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+ std::make_shared<RpcCertificateVerifierSimple>();
+ bool mSetup = false;
+ // The function invoked after connection and handshake. By default, it is
+ // |defaultPostConnect| that sends |kMessage| to the client.
+ std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> mPostConnect =
+ Server::defaultPostConnect;
+
+ void join() {
+ if (mThread != nullptr) {
+ mThread->join();
+ mThread = nullptr;
+ }
+ }
+
+ static AssertionResult defaultPostConnect(RpcTransport* serverTransport,
+ FdTrigger* fdTrigger) {
+ std::string message(kMessage);
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(),
+ message.size());
+ if (status != OK) return AssertionFailure() << statusToString(status);
+ return AssertionSuccess();
+ }
+ };
+
+ class Client {
+ public:
+ explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
+ Client(Client&&) = default;
+ [[nodiscard]] AssertionResult setUp() {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ mFdTrigger = FdTrigger::make();
+ mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
+ if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
+ return AssertionSuccess();
+ }
+ RpcTransportCtx* getCtx() const { return mCtx.get(); }
+ std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+ return mCertVerifier;
+ }
+ // connect() and do handshake
+ bool setUpTransport() {
+ mFd = mConnectToServer();
+ if (!mFd.ok()) return AssertionFailure() << "Cannot connect to server";
+ mClientTransport = mCtx->newTransport(std::move(mFd), mFdTrigger.get());
+ return mClientTransport != nullptr;
+ }
+ AssertionResult readMessage(const std::string& expectedMessage = kMessage) {
+ LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed");
+ std::string readMessage(expectedMessage.size(), '\0');
+ status_t readStatus =
+ mClientTransport->interruptableReadFully(mFdTrigger.get(), readMessage.data(),
+ readMessage.size());
+ if (readStatus != OK) {
+ return AssertionFailure() << statusToString(readStatus);
+ }
+ if (readMessage != expectedMessage) {
+ return AssertionFailure()
+ << "Expected " << expectedMessage << ", actual " << readMessage;
+ }
+ return AssertionSuccess();
+ }
+ void run(bool handshakeOk = true, bool readOk = true) {
+ if (!setUpTransport()) {
+ ASSERT_FALSE(handshakeOk) << "newTransport returns nullptr, but it shouldn't";
+ return;
+ }
+ ASSERT_TRUE(handshakeOk) << "newTransport does not return nullptr, but it should";
+ ASSERT_EQ(readOk, readMessage());
+ }
+
+ private:
+ ConnectToServer mConnectToServer;
+ base::unique_fd mFd;
+ std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+ std::unique_ptr<RpcTransportCtx> mCtx;
+ std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+ std::make_shared<RpcCertificateVerifierSimple>();
+ std::unique_ptr<RpcTransport> mClientTransport;
+ };
+
+ // Make A trust B.
+ template <typename A, typename B>
+ status_t trust(A* a, B* b) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ if (rpcSecurity != RpcSecurity::TLS) return OK;
+ LOG_ALWAYS_FATAL_IF(!certificateFormat.has_value());
+ auto bCert = b->getCtx()->getCertificate(*certificateFormat);
+ return a->getCertVerifier()->addTrustedPeerCertificate(*certificateFormat, bCert);
+ }
+
+ static constexpr const char* kMessage = "hello";
+ std::vector<std::unique_ptr<Server>> mServers;
+};
+
+TEST_P(RpcTransportTest, GoodCertificate) {
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+
+ server->start();
+ client.run();
+}
+
+TEST_P(RpcTransportTest, MultipleClients) {
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ std::vector<Client> clients;
+ for (int i = 0; i < 2; i++) {
+ auto& client = clients.emplace_back(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+ }
+
+ server->start();
+ for (auto& client : clients) client.run();
+}
+
+TEST_P(RpcTransportTest, UntrustedServer) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+
+ auto untrustedServer = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(untrustedServer->setUp());
+
+ Client client(untrustedServer->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(untrustedServer, &client));
+
+ untrustedServer->start();
+
+ // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+ // the client can't verify the server's identity.
+ bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(handshakeOk);
+}
+TEST_P(RpcTransportTest, MaliciousServer) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto validServer = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(validServer->setUp());
+
+ auto maliciousServer = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(maliciousServer->setUp());
+
+ Client client(maliciousServer->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(&client, validServer));
+ ASSERT_EQ(OK, trust(validServer, &client));
+ ASSERT_EQ(OK, trust(maliciousServer, &client));
+
+ maliciousServer->start();
+
+ // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+ // the client can't verify the server's identity.
+ bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(handshakeOk);
+}
+
+TEST_P(RpcTransportTest, UntrustedClient) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(&client, server));
+
+ server->start();
+
+ // For TLS, Client should be able to verify server's identity, so client should see
+ // do_handshake() successfully executed. However, server shouldn't be able to verify client's
+ // identity and should drop the connection, so client shouldn't be able to read anything.
+ bool readOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(true, readOk);
+}
+
+TEST_P(RpcTransportTest, MaliciousClient) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ Client validClient(server->getConnectToServerFn());
+ ASSERT_TRUE(validClient.setUp());
+ Client maliciousClient(server->getConnectToServerFn());
+ ASSERT_TRUE(maliciousClient.setUp());
+
+ ASSERT_EQ(OK, trust(&validClient, server));
+ ASSERT_EQ(OK, trust(&maliciousClient, server));
+
+ server->start();
+
+ // See UntrustedClient.
+ bool readOk = rpcSecurity != RpcSecurity::TLS;
+ maliciousClient.run(true, readOk);
+}
+
+TEST_P(RpcTransportTest, Trigger) {
+ std::string msg2 = ", world!";
+ std::mutex writeMutex;
+ std::condition_variable writeCv;
+ bool shouldContinueWriting = false;
+ auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
+ std::string message(kMessage);
+ auto status =
+ serverTransport->interruptableWriteFully(fdTrigger, message.data(), message.size());
+ if (status != OK) return AssertionFailure() << statusToString(status);
+
+ {
+ std::unique_lock<std::mutex> lock(writeMutex);
+ if (!writeCv.wait_for(lock, 3s, [&] { return shouldContinueWriting; })) {
+ return AssertionFailure() << "write barrier not cleared in time!";
+ }
+ }
+
+ status = serverTransport->interruptableWriteFully(fdTrigger, msg2.data(), msg2.size());
+ if (status != -ECANCELED)
+ return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
+ "should return -ECANCELLED, but it is "
+ << statusToString(status);
+ return AssertionSuccess();
+ };
+
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ // Set up client
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ // Exchange keys
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+
+ server->setPostConnect(serverPostConnect);
+
+ server->start();
+ // connect() to server and do handshake
+ ASSERT_TRUE(client.setUpTransport());
+ // read the first message. This ensures that server has finished handshake and start handling
+ // client fd. Server thread should pause at writeCv.wait_for().
+ ASSERT_TRUE(client.readMessage(kMessage));
+ // Trigger server shutdown after server starts handling client FD. This ensures that the second
+ // write is on an FdTrigger that has been shut down.
+ server->shutdown();
+ // Continues server thread to write the second message.
+ {
+ std::lock_guard<std::mutex> lock(writeMutex);
+ shouldContinueWriting = true;
+ }
+ writeCv.notify_all();
+ // After this line, server thread unblocks and attempts to write the second message, but
+ // shutdown is triggered, so write should failed with -ECANCELLED. See |serverPostConnect|.
+ // On the client side, second read fails with DEAD_OBJECT
+ ASSERT_FALSE(client.readMessage(msg2));
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
+ ::testing::ValuesIn(RpcTransportTest::getRpcTranportTestParams()),
+ RpcTransportTest::PrintParamInfo);
+
} // namespace android
int main(int argc, char** argv) {
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 7fd9f6b..8bf04cc 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -36,8 +36,7 @@
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
if (provider.ConsumeBool()) {
- auto session =
- RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+ auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
fillRandomParcelData(p, std::move(provider));
diff --git a/libs/binder/tests/unit_fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp
index b1263e8..6f054d2 100644
--- a/libs/binder/tests/unit_fuzzers/Android.bp
+++ b/libs/binder/tests/unit_fuzzers/Android.bp
@@ -51,7 +51,6 @@
cc_fuzz {
name: "binder_bpBinderFuzz",
defaults: ["binder_fuzz_defaults"],
- host_supported: false,
srcs: ["BpBinderFuzz.cpp"],
}
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index c50279b..20c5569 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -19,8 +19,15 @@
#include <commonFuzzHelpers.h>
#include <fuzzer/FuzzedDataProvider.h>
+#include <android-base/logging.h>
#include <binder/BpBinder.h>
#include <binder/IServiceManager.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <thread>
namespace android {
@@ -28,13 +35,30 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fdp(data, size);
- // TODO: In the future it would be more effective to fork a new process and then pass a BBinder
- // to your process. Right now this is not implemented because it would involved fuzzing IPC on a
- // forked process, and libfuzzer will not be able to handle code coverage. This would lead to
- // crashes that are not easy to diagnose.
- int32_t handle = fdp.ConsumeIntegralInRange<int32_t>(0, 1024);
- sp<BpBinder> bpbinder = BpBinder::create(handle);
- if (bpbinder == nullptr) return 0;
+ std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
+ (void)unlink(addr.c_str());
+
+ sp<RpcServer> server = RpcServer::make();
+
+ // use RPC binder because fuzzer can't get coverage from another process.
+ auto thread = std::thread([&]() {
+ prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+ server->setRootObject(sp<BBinder>::make());
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+ server->join();
+ });
+
+ sp<RpcSession> session = RpcSession::make();
+ status_t status;
+ for (size_t tries = 0; tries < 5; tries++) {
+ usleep(10000);
+ status = session->setupUnixDomainClient(addr.c_str());
+ if (status == OK) break;
+ }
+ CHECK_EQ(status, OK) << "Unable to connect";
+
+ sp<BpBinder> bpBinder = session->getRootObject()->remoteBinder();
// To prevent memory from running out from calling too many add item operations.
const uint32_t MAX_RUNS = 2048;
@@ -43,12 +67,16 @@
while (fdp.remaining_bytes() > 0 && count++ < MAX_RUNS) {
if (fdp.ConsumeBool()) {
- callArbitraryFunction(&fdp, gBPBinderOperations, bpbinder, s_recipient);
+ callArbitraryFunction(&fdp, gBPBinderOperations, bpBinder, s_recipient);
} else {
- callArbitraryFunction(&fdp, gIBinderOperations, bpbinder.get());
+ callArbitraryFunction(&fdp, gIBinderOperations, bpBinder.get());
}
}
+ CHECK(session->shutdownAndWait(true)) << "couldn't shutdown session";
+ CHECK(server->shutdown()) << "couldn't shutdown server";
+ thread.join();
+
return 0;
}
} // namespace android
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
index 6ca0e2f..741987f 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
@@ -52,7 +52,7 @@
const sp<IBinder::DeathRecipient>& s_recipient) -> void {
// Clean up possible leftover memory.
wp<IBinder::DeathRecipient> outRecipient(nullptr);
- bpbinder->sendObituary();
+ if (!bpbinder->isRpcBinder()) bpbinder->sendObituary();
bpbinder->unlinkToDeath(nullptr, reinterpret_cast<void*>(&kBpBinderCookie), 0,
&outRecipient);
@@ -72,7 +72,9 @@
[](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
const sp<IBinder::DeathRecipient>&) -> void { bpbinder->remoteBinder(); },
[](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
- const sp<IBinder::DeathRecipient>&) -> void { bpbinder->sendObituary(); },
+ const sp<IBinder::DeathRecipient>&) -> void {
+ if (!bpbinder->isRpcBinder()) bpbinder->sendObituary();
+ },
[](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
const sp<IBinder::DeathRecipient>&) -> void {
uint32_t uid = fdp->ConsumeIntegral<uint32_t>();
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index df308d8..5fe5e71 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -645,7 +645,10 @@
slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
return BAD_VALUE;
} else if (!mSlots[slot].mBufferState.isDequeued()) {
- BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
+ // TODO(http://b/140581935): This message is BQ_LOGW because it
+ // often logs when no actionable errors are present. Return to
+ // using BQ_LOGE after ensuring this only logs during errors.
+ BQ_LOGW("detachBuffer: slot %d is not owned by the producer "
"(state = %s)", slot, mSlots[slot].mBufferState.string());
return BAD_VALUE;
} else if (!mSlots[slot].mRequestBufferCalled) {