Skip to content

Commit

Permalink
Add FakeContext.getContentResolver()
Browse files Browse the repository at this point in the history
This avoids the following error on some devices:

    Given calling package android does not match caller's uid 2000

Refs #4639 comment <#4639 (comment)>
Fixes #4639 <#4639>
PR #5476 <#5476>

Signed-off-by: Romain Vimont <[email protected]>
  • Loading branch information
yume-chan authored and rom1v committed Nov 14, 2024
1 parent c0e2e27 commit 91373d9
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 7 deletions.
6 changes: 6 additions & 0 deletions server/build_without_gradle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ cd "$SERVER_DIR/src/main/aidl"
android/content/IOnPrimaryClipChangedListener.aidl
"$BUILD_TOOLS_DIR/aidl" -o"$GEN_DIR" -I. android/view/IDisplayFoldListener.aidl

# Fake sources to expose hidden Android types to the project
FAKE_SRC=( \
android/content/*java \
)

SRC=( \
com/genymobile/scrcpy/*.java \
com/genymobile/scrcpy/audio/*.java \
Expand All @@ -72,6 +77,7 @@ javac -encoding UTF-8 -bootclasspath "$ANDROID_JAR" \
-cp "$LAMBDA_JAR:$GEN_DIR" \
-d "$CLASSES_DIR" \
-source 1.8 -target 1.8 \
${FAKE_SRC[@]} \
${SRC[@]}

echo "Dexing..."
Expand Down
5 changes: 5 additions & 0 deletions server/src/main/java/android/content/IContentProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package android.content;

public interface IContentProvider {
// android.content.IContentProvider is hidden, this is a fake one to expose the type to the project
}
42 changes: 42 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/FakeContext.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.genymobile.scrcpy;

import com.genymobile.scrcpy.wrappers.ServiceManager;

import android.annotation.TargetApi;
import android.content.AttributionSource;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.IContentProvider;
import android.os.Binder;
import android.os.Process;

public final class FakeContext extends ContextWrapper {
Expand All @@ -17,6 +22,38 @@ public static FakeContext get() {
return INSTANCE;
}

private final ContentResolver contentResolver = new ContentResolver(this) {
@SuppressWarnings({"unused", "ProtectedMemberInFinalClass"})
// @Override (but super-class method not visible)
protected IContentProvider acquireProvider(Context c, String name) {
return ServiceManager.getActivityManager().getContentProviderExternal(name, new Binder());
}

@SuppressWarnings("unused")
// @Override (but super-class method not visible)
public boolean releaseProvider(IContentProvider icp) {
return false;
}

@SuppressWarnings({"unused", "ProtectedMemberInFinalClass"})
// @Override (but super-class method not visible)
protected IContentProvider acquireUnstableProvider(Context c, String name) {
return null;
}

@SuppressWarnings("unused")
// @Override (but super-class method not visible)
public boolean releaseUnstableProvider(IContentProvider icp) {
return false;
}

@SuppressWarnings("unused")
// @Override (but super-class method not visible)
public void unstableProviderDied(IContentProvider icp) {
// ignore
}
};

private FakeContext() {
super(Workarounds.getSystemContext());
}
Expand Down Expand Up @@ -49,4 +86,9 @@ public int getDeviceId() {
public Context getApplicationContext() {
return this;
}

@Override
public ContentResolver getContentResolver() {
return contentResolver;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.IContentProvider;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
Expand Down Expand Up @@ -64,7 +65,7 @@ private Method getRemoveContentProviderExternalMethod() throws NoSuchMethodExcep
}

@TargetApi(AndroidVersions.API_29_ANDROID_10)
private ContentProvider getContentProviderExternal(String name, IBinder token) {
public IContentProvider getContentProviderExternal(String name, IBinder token) {
try {
Method method = getGetContentProviderExternalMethod();
Object[] args;
Expand All @@ -83,11 +84,7 @@ private ContentProvider getContentProviderExternal(String name, IBinder token) {
// IContentProvider provider = providerHolder.provider;
Field providerField = providerHolder.getClass().getDeclaredField("provider");
providerField.setAccessible(true);
Object provider = providerField.get(providerHolder);
if (provider == null) {
return null;
}
return new ContentProvider(this, provider, name, token);
return (IContentProvider) providerField.get(providerHolder);
} catch (ReflectiveOperationException e) {
Ln.e("Could not invoke method", e);
return null;
Expand All @@ -104,7 +101,12 @@ void removeContentProviderExternal(String name, IBinder token) {
}

public ContentProvider createSettingsProvider() {
return getContentProviderExternal("settings", new Binder());
IBinder token = new Binder();
IContentProvider provider = getContentProviderExternal("settings", token);
if (provider == null) {
return null;
}
return new ContentProvider(this, provider, "settings", token);
}

private Method getStartActivityAsUserMethod() throws NoSuchMethodException, ClassNotFoundException {
Expand Down

0 comments on commit 91373d9

Please sign in to comment.