Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ class BlockStoreImpl(context: Context, val callerPackage: String) {
Log.d(TAG, "deleteBytesWithRequest: callerPackage: $callerPackage")
val localData = initSpByPackage()
if (request == null || localData.isNullOrEmpty()) return@withContext false
val editor = blockStoreSp.edit()
if (request.deleteAll) {
localData.keys.forEach { blockStoreSp.edit()?.remove(it)?.commit() }
localData.keys.forEach { editor?.remove(it) }
} else {
request.keys.forEach { blockStoreSp.edit()?.remove("$callerPackage:$it")?.commit() }
request.keys.forEach { editor?.remove("$callerPackage:$it") }
}
editor?.apply()
true
}

Expand Down Expand Up @@ -83,7 +85,7 @@ class BlockStoreImpl(context: Context, val callerPackage: String) {
}
val savedKey = "$callerPackage:${data.key ?: BlockstoreClient.DEFAULT_BYTES_DATA_KEY}"
val base64 = bytes.toBase64(Base64.URL_SAFE)
val bool = blockStoreSp.edit()?.putString(savedKey, base64)?.commit()
if (bool == true) bytes.size else 0
blockStoreSp.edit()?.putString(savedKey, base64)?.apply()
bytes.size
}
}
18 changes: 16 additions & 2 deletions play-services-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,22 @@
</intent-filter>
</service>

<service
android:name="org.microg.gms.constellation.ConstellationService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.constellation.service.START" />
</intent-filter>
</service>

<service
android:name="org.microg.gms.asterism.AsterismService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.asterism.service.START" />
</intent-filter>
</service>

<service android:name="org.microg.gms.DummyService">
<intent-filter>
<action android:name="com.google.android.contextmanager.service.ContextManagerService.START" />
Expand All @@ -1372,7 +1388,6 @@
<action android:name="com.google.android.gms.ads.service.HTTP" />
<action android:name="com.google.android.gms.appstate.service.START" />
<action android:name="com.google.android.gms.appusage.service.START" />
<action android:name="com.google.android.gms.asterism.service.START" />
<action android:name="com.google.android.gms.audiomodem.service.AudioModemService.START" />
<action android:name="com.google.android.gms.auth.account.authapi.START" />
<action android:name="com.google.android.gms.auth.account.authenticator.auto.service.START" />
Expand All @@ -1398,7 +1413,6 @@
<action android:name="com.google.android.gms.chromesync.service.START" />
<action android:name="com.google.android.gms.common.download.START" />
<action android:name="com.google.android.gms.config.START" />
<action android:name="com.google.android.gms.constellation.service.START" />
<action android:name="com.google.android.gms.deviceconnection.service.START" />
<action android:name="com.google.android.gms.enterprise.loader.service.START" />
<action android:name="com.google.android.gms.facs.internal.service.START" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,8 @@ public synchronized static long getCurrentDelay() {
long delay = currentDelay == 0 ? 5000 : currentDelay;
if (currentDelay < 60000) currentDelay += 10000;
if (currentDelay >= 60000 && currentDelay < 600000) currentDelay += 60000;
return delay;
long jitter = (long) (Math.random() * 3000);
return delay + jitter;
}

public synchronized static void resetCurrentDelay() {
Expand Down Expand Up @@ -797,7 +798,7 @@ private static void tryClose(Closeable closeable) {
}
}

private static void closeAll() {
static void closeAll() {
logd(null, "Closing all sockets...");
tryClose(inputStream);
tryClose(outputStream);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.util.Log;

Expand All @@ -40,13 +41,43 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
private static boolean registered = false;

/**
* "Project Svelte" is just there to f**k things up...
* Modern network callback handling for API 24+
*/
public synchronized static void register(Context context) {
public synchronized static void register(final Context context) {
if (SDK_INT >= 24 && !registered) {
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
context.getApplicationContext().registerReceiver(new TriggerReceiver(), intentFilter);
registered = true;
try {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm != null) {
cm.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
Log.d(TAG, "Default network available, triggering GCM connection check");
McsService.resetCurrentDelay();
Intent intent = new Intent(ACTION_CONNECT, null, context, McsService.class);
intent.putExtra(EXTRA_REASON, "network_available");
try {
new ForegroundServiceContext(context).startService(intent);
} catch (Exception e) {
Log.w(TAG, "Error starting McsService on network available: " + e.getMessage());
}
}

@Override
public void onLost(Network network) {
Log.d(TAG, "Default network lost, closing active GCM socket");
McsService.closeAll();
}
});
registered = true;
}
} catch (Exception e) {
Log.w(TAG, "Failed to register default network callback: " + e.getMessage());
}
if (!registered) {
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
context.getApplicationContext().registerReceiver(new TriggerReceiver(), intentFilter);
registered = true;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,13 @@ public class GServicesProvider extends ContentProvider {
private static final String TAG = "GmsServicesProvider";

private DatabaseHelper databaseHelper;
private Map<String, String> cache = new HashMap<String, String>();
private Set<String> cachedPrefixes = new HashSet<String>();
private final Map<String, String> cache = java.util.Collections.synchronizedMap(new java.util.LinkedHashMap<String, String>(128, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > 500;
}
});
private final Set<String> cachedPrefixes = java.util.Collections.synchronizedSet(new HashSet<String>());

@Override
public boolean onCreate() {
Expand All @@ -68,32 +73,43 @@ private String getCallingPackageName() {
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
MatrixCursor cursor = new MatrixCursor(new String[]{"name", "value"});
if (PREFIX_URI.equals(uri)) {
for (String prefix : selectionArgs) {
if (!cachedPrefixes.contains(prefix)) {
cache.putAll(databaseHelper.search(prefix + "%"));
cachedPrefixes.add(prefix);
}
if (selectionArgs != null) {
for (String prefix : selectionArgs) {
if (!cachedPrefixes.contains(prefix)) {
Map<String, String> searched = databaseHelper.search(prefix + "%");
if (searched != null) {
cache.putAll(searched);
}
cachedPrefixes.add(prefix);
}

for (String name : cache.keySet()) {
if (name.startsWith(prefix)) {
String value = cache.get(name);
if (value != null) {
cursor.addRow(new String[]{name, value});
synchronized (cache) {
for (String name : cache.keySet()) {
if (name.startsWith(prefix)) {
String value = cache.get(name);
if (value != null) {
cursor.addRow(new String[]{name, value});
}
}
}
}
}
}
} else {
for (String name : selectionArgs) {
String value;
if (cache.containsKey(name)) {
value = cache.get(name);
} else {
value = databaseHelper.get(name);
cache.put(name, value);
}
if (value != null) {
cursor.addRow(new String[]{name, value});
if (selectionArgs != null) {
for (String name : selectionArgs) {
String value;
if (cache.containsKey(name)) {
value = cache.get(name);
} else {
value = databaseHelper.get(name);
if (value != null) {
cache.put(name, value);
}
}
if (value != null) {
cursor.addRow(new String[]{name, value});
}
}
}
}
Expand All @@ -118,17 +134,34 @@ public int delete(Uri uri, String selection, String[] selectionArgs) {

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int callingUid = android.os.Binder.getCallingUid();
int myUid = android.os.Process.myUid();
if (callingUid != myUid && callingUid != 1000 && callingUid != 0) {
if (!org.microg.gms.common.PackageUtils.callerHasGooglePackagePermission(getContext(), org.microg.gms.common.GooglePackagePermission.EXTENDED_ACCESS)) {
Log.w(TAG, "Unauthorized update attempt on GServicesProvider from UID: " + callingUid);
throw new SecurityException("Permission denied: writing to GServices requires system privileges or Google authorization");
}
}

Log.d(TAG, "update caller=" + getCallingPackageName() + " table=" + uri.getLastPathSegment()
+ " name=" + values.getAsString("name") + " value=" + values.getAsString("value"));
+ " name=" + (values != null ? values.getAsString("name") : null)
+ " value=" + (values != null ? values.getAsString("value") : null));
if (values == null) return 0;
if (uri.equals(MAIN_URI)) {
databaseHelper.put("main", values);
} else if (uri.equals(OVERRIDE_URI)) {
databaseHelper.put("override", values);
}
String name = values.getAsString("name");
cache.remove(name);
Iterator<String> iterator = cachedPrefixes.iterator();
while (iterator.hasNext()) if (name.startsWith(iterator.next())) iterator.remove();
if (name != null) {
cache.remove(name);
synchronized (cachedPrefixes) {
Iterator<String> iterator = cachedPrefixes.iterator();
while (iterator.hasNext()) {
if (name.startsWith(iterator.next())) iterator.remove();
}
}
}
return 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@ public IBinder onBind(Intent intent) {
return (new AbstractThreadedSyncAdapter(this, true) {
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d(TAG, "unimplemented Method: onPerformSync");
if (account == null) return;
Log.d(TAG, "onPerformSync for account: " + account.name + " authority: " + authority);
try {
// Gracefully complete sync without errors to prevent SyncManager infinite retry loops
syncResult.stats.numInserts = 0;
syncResult.stats.numUpdates = 0;
syncResult.stats.numDeletes = 0;
} catch (Exception e) {
Log.w(TAG, "Error in onPerformSync", e);
}
}
}).getSyncAdapterBinder();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class TermsOfServiceActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setResult(RESULT_CANCELED)
setResult(RESULT_OK)
finish()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package org.microg.gms.asterism

import android.os.Binder
import android.os.Parcel
import android.util.Log
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.internal.ConnectionInfo
import com.google.android.gms.common.internal.GetServiceRequest
import com.google.android.gms.common.internal.IGmsCallbacks
import org.microg.gms.BaseService
import org.microg.gms.common.GmsService

private const val TAG = "AsterismService"

class AsterismService : BaseService(TAG, GmsService.ASTERISM) {

override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
Log.d(TAG, "handleServiceRequest from ${request.callingPackage}")
callback.onPostInitCompleteWithConnectionInfo(
CommonStatusCodes.SUCCESS,
AsterismServiceImpl(),
ConnectionInfo()
)
}
}

class AsterismServiceImpl : Binder() {
init {
attachInterface(null, "com.google.android.gms.asterism.internal.IAsterismService")
}

override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
Log.d(TAG, "onTransact code: $code")
reply?.writeNoException()
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* SPDX-FileCopyrightText: 2026 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package org.microg.gms.constellation

import android.os.Binder
import android.os.Parcel
import android.util.Log
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.internal.ConnectionInfo
import com.google.android.gms.common.internal.GetServiceRequest
import com.google.android.gms.common.internal.IGmsCallbacks
import org.microg.gms.BaseService
import org.microg.gms.common.GmsService

private const val TAG = "ConstellationService"

class ConstellationService : BaseService(TAG, GmsService.CONSTELLATION) {

override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
Log.d(TAG, "handleServiceRequest from ${request.callingPackage}")
callback.onPostInitCompleteWithConnectionInfo(
CommonStatusCodes.SUCCESS,
ConstellationServiceImpl(),
ConnectionInfo()
)
}
}

class ConstellationServiceImpl : Binder() {
init {
attachInterface(null, "com.google.android.gms.constellation.internal.IConstellationService")
}

override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
Log.d(TAG, "onTransact code: $code")
reply?.writeNoException()
return true
}
}
Loading