Not to the best of my knowledge.
The way I've implemented it in Chromium's zlib was using the available OS functionality:
https://cs.chromium.org/chromium/src/third_party/zlib/arm_features.c?l=29
It is also relevant to mention that the crc32 instructions on ARMv8 are part of the crypto extensions that are optional on ARMv8 and mandatory on ARMv8-1. It also means that runtime feature detection is necessary, for further details, please check:
https://cs.chromium.org/chromium/src/third_party/zlib/BUILD.gn?l=64
I would avoid reading directly from /proc/cpuinfo, as that may not be available in some contexts (as also depending on the Android flavor, it may be a false negative).
In Chromium, zlib will run both in a privileged context (i.e. part of the network code in the main browser process) as also in a sandboxed context (i.e. part of the RendererProcess in a tab). In the RendererProcess, reading from /proc/cpuinfo should fail.
A sledgehammer approach would be to install a signal handler and execute the instruction with inline asm, that would cause a fault if the instruction is not available (and could be captured by the handler). Not recommended, though.
The aforementioned example (https://github.com/torvalds/linux/blob/master/Documentation/arm64/cpu-feature-registers.txt) worked in 1 ARM board I've tested (MachiatoBin) but failed in 2 others (rock64 and nanopi m4).
The approach implemented in Chromium works on all the boards (as also a few cellphones I've tested).
Another detail about getauxval: the correct flag will change if running on 32bits or 64bits. So in 64bits it would be HWCAP_CRC32, while in 32bits it would be HWCAP2_CRC32.
About the sledgehammer approach: Signals are prone to race conditions plus you would still rely on the use of OS specific APIs (i.e. to install the signal handler).
Finally, depending on the context, if a given task crashes (even if by design and isolated from the execution context) it will will trigger red flags.
This is a point (i.e. feature detection) where life is way easier on x86.
That being said, it may be an acceptable compromise to rely on the OS features. We have being shipping the linked code in Chromium since release M66 (current stable is M72), first landed almost one year ago with no ill reports.
One consideration on Android was that internally the NDK may implement android_getCpuFeatures() using a dlopen()/dlsym() and that can add around 500us to 1000us at first startup, which is why we cache the result of the CPU feature detection.
Another consideration for multithreaded apps (like Chromium) was the need for a thread barrier (i.e. pthread_once_t) to avoid race conditions while performing the CPU feature detection.