{"record":{"id":"4a8e1275d1a7a50a","repo":"microg/GmsCore","slug":"caller-is-not-services-core","errorCode":null,"errorMessage":"Caller is not Services Core","messagePattern":"Caller is not Services Core","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"error","filePath":"play-services-wearable/src/main/java/com/google/android/gms/wearable/WearableListenerService.java","lineNumber":145,"sourceCode":"    }\n\n    @Override\n    public void onPeerDisconnected(Node peer) {\n    }\n\n    private class Listener extends IWearableListener.Stub {\n        private int knownGoodUid = -1;\n\n        private boolean post(Runnable runnable) {\n            int callingUid = Binder.getCallingUid();\n            if (callingUid != knownGoodUid) {\n                // TODO: Verify Gms is calling\n                String[] packagesForUid = getPackageManager().getPackagesForUid(callingUid);\n                if (packagesForUid != null) {\n                    if (Arrays.asList(packagesForUid).contains(GMS_PACKAGE_NAME)) {\n                        knownGoodUid = callingUid;\n                    } else {\n                        throw new SecurityException(\"Caller is not Services Core\");\n                    }\n                }\n            }\n            synchronized (lock) {\n                if (disconnected) {\n                    return false;\n                }\n                serviceHandler.post(runnable);\n                return true;\n            }\n        }\n\n        @Override\n        public void onDataChanged(final DataHolder data) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onDataChanged(new DataEventBuffer(data));","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-wearable/src/main/java/com/google/android/gms/wearable/WearableListenerService.java#L127-L163","documentation":"WearableListenerService.onBind/onStartCommand (post) validates that the calling UID belongs to Google Play services (GMS package) before dispatching wearable events. If the caller's packages, looked up via getPackagesForUid, do not include GMS_PACKAGE_NAME, a SecurityException is thrown. This protects the listener from spoofed Intents sent by other apps.","triggerScenarios":"Another app (or a test harness) sends an explicit Intent to WearableListenerService (action com.google.android.gms.wearable.DATA_CHANGED etc.) with a UID not owned by Google Play services; the service handles it via onDataChanged/onMessageReceived/onPeerConnected/onPeerDisconnected/onConnectedNodes/onConnectedCapabilityChanged and post() throws.","commonSituations":"Developers manually broadcasting fake wearable Intents to test the listener; running the app on a device without a properly installed/signed Play Services package; custom ROMs with unsigned GmsCore; instrumentation tests binding to the service directly.","solutions":["Ensure wearable events come only from the platform/Play services routing (use the Wearable DataClient/MessageClient APIs instead of manual Intents).","On custom ROMs, install a properly signed GmsCore (e.g. microG signed variant) so the caller UID maps to the GMS package.","In tests, mock the wearable clients rather than delivering Intents directly to WearableListenerService.","Check getPackagesForUid(callingUid) in a debugging session to identify which package actually sent the Intent."],"exampleFix":"// before\ncontext.startService(new Intent(context, MyListenerService.class)\n    .setAction(DataMapListenerIntentAction));\n\n// after\nWearable.getDataClient(context).addListener(myListener); // let Play services deliver events","handlingStrategy":"try-catch","validationCode":"String[] pkgs = getPackageManager().getPackagesForUid(callingUid);\nboolean fromGms = pkgs != null && Arrays.asList(pkgs).contains(\"com.google.android.gms\");","typeGuard":null,"tryCatchPattern":"try {\n    listenerService.onMessageReceived(event);\n} catch (SecurityException e) {\n    Log.w(TAG, \"Untrusted wearable event caller\", e);\n}","preventionTips":["Only send wearable data via Wearable API clients","Do not spoof listener Intents in tests; use mocks","Verify GmsCore signing on modified ROMs"],"tags":["android","security","wearable","intent-spoofing"],"backgroundTag":"permission-denied","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}