Require Android NDK r27c from premake

Move the validation of this requirement from `build.rive.for.sh` into our core build system.

Diffs=
52c045aaf7 Require Android NDK r27c from premake (#8900)

Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
diff --git a/.rive_head b/.rive_head
index 9684d81..bd53f77 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-d5a774b4b46a147fd72e3ffd9dc730ab313d4a13
+52c045aaf73d9dac513a68c86323c956c0063136
diff --git a/build/rive_build_config.lua b/build/rive_build_config.lua
index 52970d5..3f237cc 100644
--- a/build/rive_build_config.lua
+++ b/build/rive_build_config.lua
@@ -81,7 +81,7 @@
         {
             'runtime',
             'Build the static library specifically targeting our runtimes',
-        }
+        },
     },
     default = 'system',
 })
@@ -183,10 +183,10 @@
 })
 
 newoption({
-    trigger= "toolsversion",
-    value="msvc_toolsversion",
-    description = "specify the version of the compiler tool. On windows thats the msvc version which affects both clang and msvc outputs.",
-    default= 'latest'
+    trigger = 'toolsversion',
+    value = 'msvc_toolsversion',
+    description = 'specify the version of the compiler tool. On windows thats the msvc version which affects both clang and msvc outputs.',
+    default = 'latest',
 })
 
 -- This is just to match our old windows config. Rive Native specifically sets
@@ -252,10 +252,10 @@
 end
 
 -- for latest builds we leave toolsversion unset so that it automatically chooses the latest version
-filter({"options:toolsversion != latest"})
+filter({ 'options:toolsversion != latest' })
 do
     -- this is because unreal "prefers" certain msvc versions so we try to match it from the python build script
-    toolsversion(_OPTIONS["toolsversion"])
+    toolsversion(_OPTIONS['toolsversion'])
 end
 
 filter({ 'system:windows', 'options:toolset=clang' })
@@ -353,9 +353,42 @@
 if _OPTIONS['os'] == 'android' then
     pic('on') -- Position-independent code is required for NDK libraries.
 
-    ndk = os.getenv('NDK_PATH') or os.getenv('ANDROID_NDK')
-    if not ndk then
-        error('export $NDK_PATH or $ANDROID_NDK')
+    -- Detect the NDK.
+    EXPECTED_NDK_VERSION = 'r27c'
+    ndk = os.getenv('NDK_PATH') or os.getenv('ANDROID_NDK') or '<undefined>'
+    local ndk_version = '<undetected>'
+    local f = io.open(ndk .. '/source.properties', 'r')
+    if f then
+        for line in f:lines() do
+            local match = line:match('^Pkg.ReleaseName = (.+)$')
+            if match then
+                ndk_version = match
+                break
+            end
+        end
+        f:close()
+    end
+    if ndk_version ~= EXPECTED_NDK_VERSION then
+        print()
+        print('** Rive requires Android NDK version ' .. EXPECTED_NDK_VERSION .. ' **')
+        print()
+        print('To install via Android Studio:')
+        print('  - Settings > SDK Manager > SDK Tools')
+        print('  - Check "Show Package Details" at the bottom')
+        print('  - Select 27.2.12479018 under "NDK (Side by side)"')
+        print('  - Note the value of "Android SDK Location"')
+        print()
+        print('Then set the ANDROID_NDK environment variable:')
+        print('  - export ANDROID_NDK="<Android SDK Location>/ndk/27.2.12479018"')
+        print()
+        error(
+            'Unsupported Android NDK\n  ndk: '
+                .. ndk
+                .. '\n  version: '
+                .. ndk_version
+                .. '\n  expected: '
+                .. EXPECTED_NDK_VERSION
+        )
     end
 
     local ndk_toolchain = ndk .. '/toolchains/llvm/prebuilt'
diff --git a/tests/gm/gmmain.cpp b/tests/gm/gmmain.cpp
index fb2763a..64e36c1 100644
--- a/tests/gm/gmmain.cpp
+++ b/tests/gm/gmmain.cpp
@@ -70,6 +70,14 @@
         {
             continue; // A different process already drew this gm.
         }
+#ifdef RIVE_ANDROID
+        if (gm->name().find("feather") != std::string::npos)
+        {
+            // Don't support or test feathering on Android until MSAA is
+            // implemented and device-specific crashes are resolved.
+            continue;
+        }
+#endif
         gm->onceBeforeDraw();
 
         dump_gm(gm.get());