diff --git a/BUILD.gn b/BUILD.gn index dec3d6f902..f8707dae8f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -88,6 +88,9 @@ if (!build_with_chromium) { ] } } + if (target_os == "android") { + deps += [ "tools_webrtc:binary_version_check" ] + } } } diff --git a/call/BUILD.gn b/call/BUILD.gn index 764aa33aef..e496cebb90 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -8,6 +8,14 @@ import("../webrtc.gni") +rtc_library("version") { + sources = [ + "version.cc", + "version.h", + ] + visibility = [ ":*" ] +} + rtc_library("call_interfaces") { sources = [ "audio_receive_stream.cc", @@ -254,6 +262,7 @@ rtc_library("call") { ":rtp_receiver", ":rtp_sender", ":simulated_network", + ":version", ":video_stream_api", "../api:array_view", "../api:callfactory_api", diff --git a/call/call.cc b/call/call.cc index ca6973238e..6f407fc0f0 100644 --- a/call/call.cc +++ b/call/call.cc @@ -31,6 +31,7 @@ #include "call/receive_time_calculator.h" #include "call/rtp_stream_receiver_controller.h" #include "call/rtp_transport_controller_send.h" +#include "call/version.h" #include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h" #include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h" @@ -624,6 +625,10 @@ Call::Call(Clock* clock, RTC_DCHECK(config.trials != nullptr); RTC_DCHECK(worker_thread_->IsCurrent()); + // Do not remove this call; it is here to convince the compiler that the + // WebRTC source timestamp string needs to be in the final binary. + LoadWebRTCVersionInRegister(); + call_stats_->RegisterStatsObserver(&receive_side_cc_); module_process_thread_->process_thread()->RegisterModule( diff --git a/call/version.cc b/call/version.cc new file mode 100644 index 0000000000..921bef0066 --- /dev/null +++ b/call/version.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "call/version.h" + +namespace webrtc { + +// The timestamp is always in UTC. +const char* const kSourceTimestamp = "WebRTC source stamp 2020-12-14T14:30:00"; + +void LoadWebRTCVersionInRegister() { + // Using volatile to instruct the compiler to not optimize `p` away even + // if it looks unused. + const char* volatile p = kSourceTimestamp; + static_cast(p); +} + +} // namespace webrtc diff --git a/call/version.h b/call/version.h new file mode 100644 index 0000000000..d476e0e108 --- /dev/null +++ b/call/version.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef CALL_VERSION_H_ +#define CALL_VERSION_H_ + +// LoadWebRTCVersionInRegistry is a helper function that loads the pointer to +// the WebRTC version string into a register. While this function doesn't do +// anything useful, it is needed in order to avoid that compiler optimizations +// remove the WebRTC version string from the final binary. + +namespace webrtc { + +void LoadWebRTCVersionInRegister(); + +} // namespace webrtc + +#endif // CALL_VERSION_H_ diff --git a/tools_webrtc/BUILD.gn b/tools_webrtc/BUILD.gn new file mode 100644 index 0000000000..ee9a734107 --- /dev/null +++ b/tools_webrtc/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +if (target_os == "android") { + action("binary_version_check") { + testonly = true + script = "binary_version_check.py" + deps = [ "../sdk/android:libjingle_peerconnection_so" ] + inputs = [ "$root_out_dir/libjingle_peerconnection_so.so" ] + outputs = [ "$root_out_dir/webrtc_binary_version_check" ] + args = [ "libjingle_peerconnection_so.so" ] + } +} diff --git a/tools_webrtc/binary_version_check.py b/tools_webrtc/binary_version_check.py new file mode 100644 index 0000000000..cc5d96172c --- /dev/null +++ b/tools_webrtc/binary_version_check.py @@ -0,0 +1,34 @@ +# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +import re +import subprocess +import sys + +WEBRTC_VERSION_RE = re.compile( + r'WebRTC source stamp [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}' +) + + +if __name__ == '__main__': + args = sys.argv + if len(args) != 2: + print('Usage: binary_version_test.py ') + exit(1) + filename = sys.argv[1] + output = subprocess.check_output(['strings', filename]) + strings_in_binary = output.decode('utf-8').splitlines() + for symbol in strings_in_binary: + if WEBRTC_VERSION_RE.match(symbol): + with open('webrtc_binary_version_check', 'w') as f: + f.write(symbol) + exit(0) + print('WebRTC source timestamp not found in "%s"' % filename) + print('Check why "kSourceTimestamp" from call/version.cc is not linked ' + '(or why it has been optimized away by the compiler/linker)') + exit(1) diff --git a/tools_webrtc/version_updater/update_version.py b/tools_webrtc/version_updater/update_version.py new file mode 100644 index 0000000000..5875c685fb --- /dev/null +++ b/tools_webrtc/version_updater/update_version.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +"""Script to auto-update the WebRTC source version in call/version.cc""" + +import argparse +import datetime +import logging +import os +import re +import subprocess +import sys + + +def FindSrcDirPath(): + """Returns the abs path to the src/ dir of the project.""" + src_dir = os.path.dirname(os.path.abspath(__file__)) + while os.path.basename(src_dir) != 'src': + src_dir = os.path.normpath(os.path.join(src_dir, os.pardir)) + return src_dir + + +UPDATE_BRANCH_NAME = 'webrtc_version_update' +CHECKOUT_SRC_DIR = FindSrcDirPath() + + +def _RemovePreviousUpdateBranch(): + active_branch, branches = _GetBranches() + if active_branch == UPDATE_BRANCH_NAME: + active_branch = 'master' + if UPDATE_BRANCH_NAME in branches: + logging.info('Removing previous update branch (%s)', + UPDATE_BRANCH_NAME) + subprocess.check_call(['git', 'checkout', active_branch]) + subprocess.check_call(['git', 'branch', '-D', UPDATE_BRANCH_NAME]) + logging.info('No branch to remove') + + +def _GetBranches(): + """Returns a tuple (active, branches). + + 'active' is a string with name of the currently active branch, while + 'branches' is the list of all branches. + """ + lines = subprocess.check_output(['git', 'branch']).splitlines() + branches = [] + active = '' + for line in lines: + if '*' in line: + # The assumption is that the first char will always be the '*'. + active = line[1:].strip() + branches.append(active) + else: + branch = line.strip() + if branch: + branches.append(branch) + return active, branches + + +def _CreateUpdateBranch(): + logging.info('Creating update branch: %s', UPDATE_BRANCH_NAME) + subprocess.check_call(['git', 'checkout', '-b', UPDATE_BRANCH_NAME]) + + +def _UpdateWebRTCVersion(filename): + with open(filename) as f: + content = f.read() + d = datetime.datetime.utcnow() + # pylint: disable=line-too-long + new_content = re.sub( + r'WebRTC source stamp [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}', + r'WebRTC source stamp %02d-%02d-%02dT%02d:%02d:%02d' % (d.year, + d.month, + d.day, + d.hour, + d.minute, + d.second), + content, + flags=re.MULTILINE) + # pylint: enable=line-too-long + with open(filename, 'w') as f: + f.write(new_content) + + +def _IsTreeClean(): + stdout = subprocess.check_output(['git', 'status', '--porcelain']) + if len(stdout) == 0: + return True + return False + + +def _LocalCommit(): + logging.info('Committing changes locally.') + d = datetime.datetime.utcnow() + commit_msg = ('Update WebRTC code version (%02d-%02d-%02dT%02d:%02d:%02d).' + '\n\nBugs: None') + commit_msg = commit_msg % (d.year, d.month, d.day, d.hour, d.minute, + d.second) + subprocess.check_call(['git', 'add', '--update', '.']) + subprocess.check_call(['git', 'commit', '-m', commit_msg]) + + +def _UploadCL(commit_queue_mode): + """Upload the committed changes as a changelist to Gerrit. + + commit_queue_mode: + - 2: Submit to commit queue. + - 1: Run trybots but do not submit to CQ. + - 0: Skip CQ, upload only. + """ + cmd = ['git', 'cl', 'upload', '--force', '--bypass-hooks', + '--cc=""', '--bypass-watchlist'] + if commit_queue_mode >= 2: + logging.info('Sending the CL to the CQ...') + cmd.extend(['--use-commit-queue']) + elif commit_queue_mode >= 1: + logging.info('Starting CQ dry run...') + cmd.extend(['--cq-dry-run']) + subprocess.check_call(cmd) + + +def main(): + logging.basicConfig(level=logging.INFO) + p = argparse.ArgumentParser() + p.add_argument('--clean', + action='store_true', + default=False, + help='Removes any previous local update branch.') + opts = p.parse_args() + + if opts.clean: + _RemovePreviousUpdateBranch() + + version_filename = os.path.join(CHECKOUT_SRC_DIR, 'call', 'version.cc') + _CreateUpdateBranch() + _UpdateWebRTCVersion(version_filename) + if _IsTreeClean(): + logging.info("No WebRTC version change detected, skipping CL.") + else: + _LocalCommit() + logging.info('Uploading CL...') + _UploadCL(1) + return 0 + + +if __name__ == '__main__': + sys.exit(main())