A: Toybox started back in 2006 when I (Rob Landley) handed off BusyBox maintainership and started over from scratch on a new codebase after a protracted licensing argument took all the fun out of working on BusyBox.
Toybox was just a personal project until it got relaunched in November 2011 with a new goal to make Android self-hosting. This involved me relicensing my own code, which made people who had never used or participated in the project loudly angry. The switch came after a lot of thinking about licenses and the transition to smartphones, which led to a 2013 talk laying out a strategy to make Android self-hosting using toybox. This helped bring it to Android's attention, and they merged it into Android M.
The unfixable problem with busybox was licensing: BusyBox predates Android by almost a decade, but Android still doesn't ship with it because GPLv3 came out around the same time Android did and caused many people to throw out the GPLv2 baby with the GPLv3 bathwater. Android explicitly discourages use of GPL and LGPL licenses in its products, and has gradually reimplemented historical GPL components (such as its bluetooth stack) under the Apache license. Apple's less subtle response was to freeze xcode at the last GPLv2 releases (GCC 4.2.1 with binutils 2.17) for over 5 years while sponsoring the development of new projects (clang/llvm/lld) to replace them, implementing a new SMB server from scratch to replace samba, switching bash with zsh, and so on. Toybox itself exists because somebody in a legacy position just wouldn't shut up about GPLv3, otherwise I would probably still happily be maintaining BusyBox. (For more on how I wound up working on busybox in the first place, see here.)
A: Only at the start of a sentence. The command name is all lower case so it seems silly to capitalize the project name, but not capitalizing the start of sentences is awkward, so... compromise. (It is _not_ "ToyBox".)
A: Our longstanding rule of thumb is to try to run and build on hardware and distributions released up to 7 years ago, and feel ok dropping support for stuff older than that. (This is a little longer than Ubuntu's Long Term Support, but not by much.)
My original theory was "4 to 5 of the 18-month cycles of moore's law should cover the vast majority of the installed base of PC hardware", loosely based on some research I did back in 2003 and updated in 2006 which said that low end systems were 2 iterations of moore's law below the high end systems, and that another 2-3 iterations should cover the useful lifetime of most systems no longer being sold but still in use and potentially being upgraded to new software releases.
That analysis missed industry changes in the 1990's that stretched the gap from low end to high end from 2 cycles to 4 cycles, and ignored the switch from PC to smartphone cutting off the R&D air supply of the laptop market. Meanwhile the Moore's Law s-curve started bending back down (as they always do) back in 2000, and these days is pretty flat: the drive for faster clock speeds stumbled and died, with the subsequent drive to go "wide" maxing out for most applications around 4x SMP with maybe 2 megabyte caches. These days the switch from exponential to linear growth in hardware capabilities is common knowledge and widely accepted.
But the 7 year rule of thumb stuck around anyway: if a kernel or libc feature is less than 7 years old, I try to have a build-time configure test for it to let the functionality cleanly drop out. I also keep old Ubuntu images around in VMs to perform the occasional defconfig build there to see what breaks. (I'm not perfect about this, but I accept bug reports.)
A: Toybox targets quarterly releases (a similar schedule to the Linux kernel) because Martin Michlmayr's excellent talk on the subject was convincing. This is actually two questions, "why have releases" and "why schedule them".
Releases provide synchronization points where the developers certify "it worked for me". Each release is a known version with predictable behavior, and right or wrong at least everyone should be seeing similar results so might be able to google an unexpected outcome. Releases focus end-user testing on specific versions where issues can be reproduced, diagnosed, and fixed. Releases also force the developers to do periodic tidying, packaging, documentation review, finish up partially implemented features languishing in their private trees, and give regular checkpoints to measure progress.
Changes accumulate over time: different feature sets, data formats, control knobs... Toybox's switch from "ls -q" to "ls -b" as the default output format was not-a-bug-it's-a "design improvement", but the difference is academic if the change breaks somebody's script. Releases give you the option to schedule upgrades as maintenance, not to rock the boat just now, and use a known working release version until later.
The counter-argument is that "continuous integration" can be made robust with sufficient automated testing. But like the waterfall method, this places insufficent emphasis on end-user feedback and learning from real world experience. Developer testing is either testing that the code does what the developers expect given known inputs running in an established environment, or it's regression testing against bugs previously found in the field. No plan survives contact with the enemy, and technology always breaks once it leaves the lab and encounters real world data and use cases in new runtime and build environments.
The best way to give new users a reasonable first experience is to point them at specific stable versions where development quiesced and extra testing occurred. There will still be teething troubles, but multiple people experiencing the _same_ teething troubles can potentially help each other out.
Releases on a schedule are better than releases "when it's ready" for the same reason a regularly scheduled bus beats one that leaves when it's "full enough": the schedule lets its users make plans. Even if the bus leaves empty you know when the next one arrives so missing this one isn't a disaster. and starting the engine to leave doesn't provoke a last-minute rush of nearby not-quite-ready passengers racing to catch it causing further delay and repeated start/stop cycles as it ALMOST leaves. (The video in the first paragraph goes into much greater detail.)
A: Toybox is written in C. There are longer writeups of the design ideas and a code walkthrough, and the about page summarizes what we're trying to accomplish, but here's a quick start:
Toybox uses the standard three stage configure/make/install build, in this case "make defconfig; make; make install". Type "make help" to see available make targets.
The configure stage is copied from the Linux kernel (in the "kconfig" directory), and saves your selections in the file ".config" at the top level. The "make defconfig" target selects the maximum sane configuration (enabling all the commands and features that aren't unfinished, or only intended as examples, or debug code...) and is probably what you want. You can use "make menuconfig" to manually select specific commands to include, through an interactive menu (cursor up and down, enter to descend into a sub-menu, space to select an entry, ? to see an entry's help text, esc to exit). The menuconfig help text is the same as the command's "--help" output.
The "make" stage creates a toybox binary (which is stripped, look in generated/unstripped for the debug versions), and "make install" adds a bunch of symlinks to toybox under the various command names. Toybox determines which command to run based on the filename, or you can use the "toybox" name in which case the first argument is the command to run (ala "toybox ls -l").
You can also build individual commands as standalone executables, ala "make sed cat ls". The "make change" target builds all of them, as in "change for a $20".
The main() function is in main.c at the top level, along with setup plumbing and selecting which command to run this time. The function toybox_main() in the same file implements the "toybox" multiplexer command that lists and selects the other commands.
The individual command implementations are under "toys", and are grouped into categories (mostly based on which standard they come from, posix, lsb, android...) The "pending" directory contains unfinished commands, and the "examples" directory contains example code that aren't really useful commands. Commands in those two directories are _not_ selected by defconfig. (Most of the files in the pending directory are third party submissions that have not yet undergone proper code review.)
Common infrastructure shared between commands is under "lib". Most commands call lib/args.c to parse their command line arguments before calling the command's own main() function, which uses the option string in the command's NEWTOY() macro. This is similar to the libc function getopt(), but more powerful, and is documented at the top of lib/args.c. A NULL option string prevents this code from being called for that command.
The build/install infrastructure is shell scripts under "scripts" (starting with scripts/make.sh and scripts/install.sh). These populate the "generated" directory with headers created from other files, which are described in the code walkthrough. All the build's temporary files live under generated, including the .o files built from the .c files (in generated/obj). The "make clean" target deletes that directory. ("make distclean" also deletes your .config and deletes the kconfig binaries that process .config.)
Each command's .c file contains all the information for that command, so adding a command to toybox means adding a single file under "toys". Usually you start a new command by copying an existing command file to a new filename (toys/examples/hello.c, toys/examples/skeleton.c, toys/posix/cat.c, and toys/posix/true.c have all been used for this purpose) and then replacing all instances of its old name with the new name (which should match the new filename), and modifying the help text, argument string, and what the code does. You might have to "make distclean" before your new command shows up in defconfig or menuconfig.
The toybox test suite lives in the "tests" directory, and is driven by scripts/test.sh and scripts/runtest.sh. From the top level you can "make tests" to test everything, or "make test_sed" to test a single command's standalone version (which should behave identically, but that's why we test). You can set TEST_HOST=1 to test the host version instead of the toybox version (in theory they should work the same), and VERBOSE=all to see diffs of the expected and actual output for all failing tests. The default VERBOSE=fail stops at the first such failure.
A: For vanilla releases, check the date on the commit tag or the example binaries against the output of "toybox --version". Between releases the --version information is in "git describe --tags" format with "tag-count-hash" showing the most recent commit tag, the number of commits since that tag, and the hash of the current commit.
Android makes its own releases on its own schedule using its own version tags, but lists corresponding upstream toybox release versions here. For more detail you can look up AOSP's git tags. (The Android Open Source Project is the "upstream" android vendors start form when making their own releases. Google's phones run AOSP versions verbatim, other vendors tend to take those releases as starting points to modify.)
If you want to find the vanilla toybox commit corresponding to an AOSP toybox version, find the most recent commit in the android log that isn't from a @google or @android address and search for it in the vanilla commit log. (The timestamp should match but the hash will differ, because each git hash includes the previous git hash in the data used to generate it so all later commits have a different hash if any of the tree's history differs; yes Linus Torvalds published 3 years before Satoshi Nakamoto.) Once you've identified the vanilla commit's hash, "git describe --tags $HASH" in the vanilla tree should give you the --version info for that one.
A: Ideally on the mailing list, although emailing the maintainer is a popular if slightly less reliable alternative. Issues submitted to github are generally dealt with less promptly, but mostly get done eventually. AOSP has its own bug reporting mechanism (although for toybox they usually forward them to the mailing list) and Android vendors usually forward them to AOSP which forwards them to the list.
Note that if we can't reproduce a bug, we probably can't fix it. Not only does this mean providing enough information for us to see the behavior ourselves, but ideally doing so in a reasonably current version. The older it is the greater the chance somebody else found and fixed it already, so the more out of date the version you're reporting a bug against the less effort we're going to put into reproducing the problem.
A: It's a Google thing. Replace /b/$NUMBER with https://issuetracker.google.com/$NUMBER to read it outside the googleplex.
A: The about page tries to explain that, and Linux Weekly News has covered toybox's history a little over the years.
Toybox is a traditional open source project created and maintained by hobbyist (volunteer) developers, originally for Linux but these days also running on Android, BSD, and MacOS. The project started in 2006 and its original author (Rob Landley) continues to maintain the open source project.
Android's base OS maintainer (Elliott Hughes, I.E. enh) ported toybox to Android in 2014, merged it into Android M (Marshmallow), and remains Android's toybox maintainer. (He explained it in his own words in this podcast, starting either 18 or 20 minutes in depending how much backstory you want.)
Android's policy for toybox development is to push patches to the open source project (submitting them via the mailing list) then "git pull" the public tree into Android's tree. To avoid merge conflicts, Android's tree doesn't change any of the existing toybox files but instead adds parallel build infrastructure off to one side. (Toybox uses a make wrapper around bash scripts, AOSP builds with soong/ninja instead and checks in a snapshot of the generated/ directory to avoid running kconfig each build). Android's changes to toybox going into the open source tree first and being pulled from there into Android keeps the two trees in sync, and makes sure each change undergoes full open source design review and discussion.
Rob acknowledges Android is by far the largest userbase for the project, but develops on a standard 64-bit Linux+glibc distro while building embedded 32-bit big-endian nommu musl systems requiring proper data alignment for work, and is not a Google employee so does not have access to the Google build cluster of powerful machines capable of running the full AOSP build in a reasonable amount of time. Rob is working to get android building under android (the list of toybox tools Android's build uses is here, and what else it needs from its build environment is here), and he hopes someday to not only make a usable development environment out of it but also nudge the base OS towards a more granular package management system allowing you to upgrade things like toybox without a complete reinstall and reboot, plus the introduction of a "posix container" within which you can not only run builds, but selinux lets you run binaries you've just built). In the meantime, Rob tests static bionic builds via the Android NDK when he remembers, but has limited time to work on toybox because it's not his day job. (The products his company makes ship toybox and they do sponsor the project's development, but it's one of many responsibilities at work.)
Elliott is the Android base OS maintainer, in which role he manages a team of engineers. He also has limited time for toybox, both because it's one of many packages he's responsible for (he maintains bionic, used to maintain dalvik...) and because he allowed himself to be promoted into management and thus spends less time coding than he does sitting in meetings where testers talk to security people about vendor issues.
Android has many other coders and security people who submit the occasional toybox patch, but of the last 1000 commits at the time of writing this FAQ entry, Elliott submitted 276 and all other google.com or android.com addresses combined totaled 17. (Rob submitted 591, leaving 116 from other sources, but for both Rob and Elliott there's a lot of "somebody else pointed out an issue, and then we wrote a patch". A lot of patches from both "Author:" lines thank someone else for the suggestion in the commit comment.)
A: Probably not. The easiest thing to do is get your issue fixed upstream in the current release, then get the newest version of the project built and running in the old environment.
Backporting fixes generally isn't something open source projects run by volunteer developers do because the goal of the project's development community is to extend and improve the project. We're happy to respond to our users' needs, but if you're coming to the us for free tech support we're going to ask you to upgrade to a current version before we try to diagnose your problem.
The volunteers are happy to fix any bugs you point out in the current versions because doing so helps everybody and makes the project better. We want to make the current version work for you. But diagnosing, debugging, and backporting fixes to old versions doesn't help anybody but you, so isn't something we do for free. The cost of volunteer tech support is using a reasonably current version of the project.
If you're using an old version built with an old compiler on an old OS (kernel and libc), there's a fairly large chance whatever problem you're seeing already got fixed, and to get that fix all you have to do is upgrade to a newer version. Diagnosing a problem that wasn't our bug means we spent time that only helps you, without improving the project. If you don't at least _try_ a current version, you're asking us for free personalized tech support.
Reproducing bugs in current versions also makes our job easier. The further back in time you are, the more work it is for us digging back in the history to figure out what we hadn't done yet in your version. If spot a problem in a git build pulled 3 days ago, it's obvious what changed and easy to fix or back out. If you ask about the current release version 3 month