Skip to content
Merged
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 @@ -136,7 +136,11 @@ public static String getOpenSourceSoftwareLicenseInfo(Context context) {
* @return The Context object of the Buddy APK or null if the Buddy APK is not installed on the device.
*/
public static Context getRemoteContext(Context context) {
return null; // TODO
try {
return context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
} catch (PackageManager.NameNotFoundException unused) {
return null;
}
}

/**
Expand All @@ -145,7 +149,11 @@ public static Context getRemoteContext(Context context) {
* @return The Resources object of the Buddy APK or null if the Buddy APK is not installed on the device.
*/
public static Resources getRemoteResources(Context context) {
return null; // TODO
try {
return context.getPackageManager().getResourcesForApplication(Constants.GMS_PACKAGE_NAME);
} catch (PackageManager.NameNotFoundException unused) {
return null;
}
}

/**
Expand Down
3 changes: 2 additions & 1 deletion play-services-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@
androidx.compose.ui.graphics,
androidx.compose.ui.geometry,
androidx.compose.ui.tooling.preview,
androidx.compose.runtime.saveable"
androidx.compose.runtime.saveable,
org.opencv"
/>
<application
android:allowBackup="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package com.google.android.gms.chimera;

import static android.os.Build.CPU_ABI;
import static android.os.Build.SUPPORTED_32_BIT_ABIS;
import static android.os.Build.SUPPORTED_64_BIT_ABIS;
import static android.os.Build.VERSION.SDK_INT;

import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Process;
import android.util.Log;

import com.google.android.gms.chimera.container.DynamiteContext;
import com.google.android.gms.chimera.container.DynamiteModuleInfo;
import com.google.android.gms.chimera.container.FilteredClassLoader;

import org.microg.gms.common.Constants;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

import dalvik.system.PathClassLoader;

public class DynamiteContextFactory {
private static final String TAG = "DynamiteContextFactory";
private static final Map<String, DynamiteContext> sContextCache = new WeakHashMap<>();
// WeakHashMap cannot be used, and there is a high probability that it will be recycled, causing ClassLoader to be rebuilt
private static final Map<String, ClassLoader> sClassLoaderCache = new HashMap<>();

public static DynamiteContext createDynamiteContext(String moduleId, Context originalContext) {
if (originalContext == null) {
Log.w(TAG, "create <DynamiteContext> Original context is null");
return null;
}
String cacheKey = moduleId + "-" + originalContext.getPackageName();
synchronized (sContextCache) {
DynamiteContext cached = sContextCache.get(cacheKey);
if (cached != null) {
Log.d(TAG, "Using cached DynamiteContext for cacheKey: " + cacheKey);
return cached;
}
}
try {
DynamiteModuleInfo moduleInfo = new DynamiteModuleInfo(moduleId);
Context gmsContext = originalContext.createPackageContext(Constants.GMS_PACKAGE_NAME, 0);
Context originalAppContext = originalContext.getApplicationContext();

DynamiteContext dynamiteContext;
if (originalAppContext == null || originalAppContext == originalContext) {
dynamiteContext = new DynamiteContext(moduleInfo, originalContext, gmsContext, null);
} else {
dynamiteContext = new DynamiteContext(moduleInfo, originalContext, gmsContext, new DynamiteContext(moduleInfo, originalAppContext, gmsContext, null));
}
moduleInfo.init(dynamiteContext);

synchronized (sContextCache) {
sContextCache.put(cacheKey, dynamiteContext);
}
Log.d(TAG, "Created and cached a new DynamiteContext for cacheKey: " + cacheKey);
return dynamiteContext;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, e);
return null;
}
}

public static ClassLoader createClassLoader(DynamiteModuleInfo moduleInfo, Context gmsContext, Context originalContext) {
String cacheKey = moduleInfo.getModuleId() + "-" + originalContext.getPackageName();
synchronized (sClassLoaderCache) {
ClassLoader cached = sClassLoaderCache.get(cacheKey);
if (cached != null) {
Log.d(TAG, "Using cached ClassLoader for cacheKey: " + cacheKey + " cached: " + cached.hashCode());
return cached;
}
}
StringBuilder nativeLoaderDirs = new StringBuilder(gmsContext.getApplicationInfo().nativeLibraryDir);
if (SDK_INT >= 23 && Process.is64Bit()) {
for (String abi : SUPPORTED_64_BIT_ABIS) {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi);
}
} else if (SDK_INT >= 21) {
for (String abi : SUPPORTED_32_BIT_ABIS) {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi);
}
} else {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(CPU_ABI);
}
ClassLoader classLoader = new PathClassLoader(gmsContext.getApplicationInfo().sourceDir, nativeLoaderDirs.toString(), new FilteredClassLoader(originalContext.getClassLoader(), moduleInfo.getMergedClasses(), moduleInfo.getMergedPackages()));
synchronized (sClassLoaderCache) {
sClassLoaderCache.put(cacheKey, classLoader);
}
Log.d(TAG, "Created and cached a new ClassLoader for cacheKey: " + cacheKey + " ClassLoader: " + classLoader.hashCode());
return classLoader;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,10 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Process;
import android.util.Log;

import androidx.annotation.RequiresApi;

import org.microg.gms.common.Constants;

import java.io.File;

import dalvik.system.PathClassLoader;

import static android.os.Build.CPU_ABI;
import static android.os.Build.SUPPORTED_32_BIT_ABIS;
import static android.os.Build.SUPPORTED_64_BIT_ABIS;
import static android.os.Build.VERSION.SDK_INT;
import com.google.android.gms.chimera.DynamiteContextFactory;

public class DynamiteContext extends ContextWrapper {
private static final String TAG = "DynamiteContext";
Expand All @@ -45,19 +33,7 @@ public DynamiteContext(DynamiteModuleInfo moduleInfo, Context base, Context gmsC
@Override
public ClassLoader getClassLoader() {
if (classLoader == null) {
StringBuilder nativeLoaderDirs = new StringBuilder(gmsContext.getApplicationInfo().nativeLibraryDir);
if (SDK_INT >= 23 && Process.is64Bit()) {
for (String abi : SUPPORTED_64_BIT_ABIS) {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi);
}
} else if (SDK_INT >= 21) {
for (String abi : SUPPORTED_32_BIT_ABIS) {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi);
}
} else {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(CPU_ABI);
}
classLoader = new PathClassLoader(gmsContext.getApplicationInfo().sourceDir, nativeLoaderDirs.toString(), new FilteredClassLoader(originalContext.getClassLoader(), moduleInfo.getMergedClasses(), moduleInfo.getMergedPackages()));
classLoader = DynamiteContextFactory.createClassLoader(moduleInfo, gmsContext, originalContext);
}
return classLoader;
}
Expand All @@ -82,23 +58,4 @@ public Context getApplicationContext() {
public Context createDeviceProtectedStorageContext() {
return new DynamiteContext(moduleInfo, originalContext.createDeviceProtectedStorageContext(), gmsContext.createDeviceProtectedStorageContext(), appContext);
}

public static DynamiteContext create(String moduleId, Context originalContext) {
try {
DynamiteModuleInfo moduleInfo = new DynamiteModuleInfo(moduleId);
Context gmsContext = originalContext.createPackageContext(Constants.GMS_PACKAGE_NAME, 0);
Context originalAppContext = originalContext.getApplicationContext();
DynamiteContext dynamiteContext;
if (originalAppContext == null || originalAppContext == originalContext) {
dynamiteContext = new DynamiteContext(moduleInfo, originalContext, gmsContext, null);
} else {
dynamiteContext = new DynamiteContext(moduleInfo, originalContext, gmsContext, new DynamiteContext(moduleInfo, originalAppContext, gmsContext, null));
}
moduleInfo.init(dynamiteContext);
return dynamiteContext;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, e);
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,14 @@
package com.google.android.gms.chimera.container;

import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.util.Log;

import com.google.android.gms.chimera.DynamiteContextFactory;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.dynamite.IDynamiteLoader;

import org.microg.gms.common.Constants;

import java.lang.reflect.Field;

public class DynamiteLoaderImpl extends IDynamiteLoader.Stub {
private static final String TAG = "GmsDynamiteLoaderImpl";

Expand All @@ -43,7 +38,7 @@ public IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String
public IObjectWrapper createModuleContextV2(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException {
Log.d(TAG, "createModuleContext for " + moduleId + " at version " + minVersion);
final Context originalContext = (Context) ObjectWrapper.unwrap(wrappedContext);
return ObjectWrapper.wrap(DynamiteContext.create(moduleId, originalContext));
return ObjectWrapper.wrap(DynamiteContextFactory.createDynamiteContext(moduleId, originalContext));
}

@Override
Expand Down
43 changes: 43 additions & 0 deletions play-services-mlkit/face-detection/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'signing'

android {
namespace "com.google.mlkit.vision.face"

compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"

buildFeatures {
aidl = true
}

defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}

compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}

apply from: '../../gradle/publish-android.gradle'

description = 'microG implementation of play-services-mlkit-face-detection'

dependencies {
// Dependencies from play-services-mlkit-face-detection:17.1.0
api project(':play-services-base')
api project(':play-services-basement')
api project(':play-services-tasks')

annotationProcessor project(":safe-parcel-processor")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ SPDX-FileCopyrightText: 2023 microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application />
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package com.google.mlkit.vision.face;

parcelable FaceDetectionOptions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package com.google.mlkit.vision.face;

parcelable FrameMetadataParcel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package com.google.mlkit.vision.face.aidls;

parcelable FaceParcel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package com.google.mlkit.vision.face.aidls;

import com.google.android.gms.dynamic.IObjectWrapper;
import java.util.List;
import com.google.mlkit.vision.face.FrameMetadataParcel;
import com.google.mlkit.vision.face.aidls.FaceParcel;

interface IFaceDetector {
void initDetector() = 0;
void close() = 1;
List<FaceParcel> detectFaces(IObjectWrapper wrapper, in FrameMetadataParcel metadata) = 2;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package com.google.mlkit.vision.face.aidls;

import com.google.mlkit.vision.face.aidls.IFaceDetector;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.mlkit.vision.face.FaceDetectionOptions;

interface IFaceDetectorCreator {
IFaceDetector newFaceDetector(IObjectWrapper context, in FaceDetectionOptions faceDetectionOptions) = 0;
}
Loading