Giter Club home page Giter Club logo

remotepreferences's Introduction

RemotePreferences

A drop-in solution for inter-app access to SharedPreferences.

Installation

1. Add the dependency to your build.gradle file:

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.crossbowffs.remotepreferences:remotepreferences:0.8'
}

2. Subclass RemotePreferenceProvider and implement a 0-argument constructor which calls the super constructor with an authority (e.g. "com.example.app.preferences") and an array of preference files to expose:

public class MyPreferenceProvider extends RemotePreferenceProvider {
    public MyPreferenceProvider() {
        super("com.example.app.preferences", new String[] {"main_prefs"});
    }
}

3. Add the corresponding entry to AndroidManifest.xml, with android:authorities equal to the authority you picked in the last step, and android:exported set to true:

<provider
    android:name=".MyPreferenceProvider"
    android:authorities="com.example.app.preferences"
    android:exported="true"/>

4. You're all set! To access your preferences, create a new instance of RemotePreferences with the same authority and the name of the preference file:

SharedPreferences prefs = new RemotePreferences(context, "com.example.app.preferences", "main_prefs");
int value = prefs.getInt("my_int_pref", 0);

WARNING: DO NOT use RemotePreferences from within IXposedHookZygoteInit.initZygote, since app providers have not been initialized at this point. Instead, defer preference loading to IXposedHookLoadPackage.handleLoadPackage.

Note that you should still use context.getSharedPreferences("main_prefs", MODE_PRIVATE) if your code is executing within the app that owns the preferences. Only use RemotePreferences when accessing preferences from the context of another app.

Also note that your preference keys cannot be null or "" (empty string).

Security

By default, all preferences have global read/write access. If this is what you want, then no additional configuration is required. However, chances are you'll want to prevent 3rd party apps from reading or writing your preferences. There are two ways to accomplish this:

  1. Use the Android permissions system built into ContentProvider
  2. Override the checkAccess method in RemotePreferenceProvider

Option 1 is the simplest to implement - just add android:readPermission and/or android:writePermission to your preference provider in AndroidManifest.xml. Unfortunately, this does not work very well if you are hooking apps that you do not control (e.g. Xposed), since you cannot modify their permissions.

Option 2 requires a bit of code, but is extremely powerful since you can control exactly which preferences can be accessed. To do this, override the checkAccess method in your preference provider class:

@Override
protected boolean checkAccess(String prefFileName, String prefKey, boolean write) {
    // Only allow read access
    if (write) {
        return false;
    }

    // Only allow access to certain preference keys
    if (!"my_pref_key".equals(prefKey)) {
        return false;
    }

    // Only allow access from certain apps
    if (!"com.example.otherapp".equals(getCallingPackage())) {
        return false;
    }

    return true;
}

Warning: when checking an operation such as getAll() or clear(), prefKey will be an empty string. If you are blacklisting certain keys, make sure to also blacklist the "" key as well!

Device encrypted preferences

By default, devices with Android N+ come with file-based encryption, which prevents RemotePreferences from accessing them before the first unlock after reboot. If preferences need to be accessed before the first unlock, the following modifications are needed.

1. Modify the provider constructor to mark the preference file as device protected:

public class MyPreferenceProvider extends RemotePreferenceProvider {
    public MyPreferenceProvider() {
        super("com.example.app.preferences", new RemotePreferenceFile[] {
            new RemotePreferenceFile("main_prefs", /* isDeviceProtected */ true)
        });
    }
}

This will cause the provider to use context.createDeviceProtectedStorageContext() to access the preferences.

2. Add support for direct boot in your manifest:

<provider
    android:name=".MyPreferenceProvider"
    android:authorities="com.example.app.preferences"
    android:exported="true"
    android:directBootAware="true"/>

3. Update your app to access shared preferences from device protected storage. If you are using PreferenceManager, call setStorageDeviceProtected(). If you are using SharedPreferences, use createDeviceProtectedStorageContext() to create the preferences. For example:

Context prefContext = context.createDeviceProtectedStorageContext();
SharedPreferences prefs = prefContext.getSharedPreferences("main_prefs", MODE_PRIVATE);

Strict mode

To maintain API compatibility with SharedPreferences, by default any errors encountered while accessing the preference provider will be ignored, resulting in default values being returned from the getter methods and apply() silently failing (we advise using commit() and checking the return value, at least). This can be caused by bugs in your code, or the user disabling your app/provider component. To detect and handle this scenario, you may opt-in to strict mode by passing an extra parameter to the RemotePreferences constructor:

SharedPreferences prefs = new RemotePreferences(context, authority, prefFileName, true);

Now, if the preference provider cannot be accessed, a RemotePreferenceAccessException will be thrown. You can handle this by wrapping your preference accesses in a try-catch block:

try {
    int value = prefs.getInt("my_int_pref", 0);
    prefs.edit().putInt("my_int_pref", value + 1).apply();
} catch (RemotePreferenceAccessException e) {
    // Handle the error
}

Why would I need this?

This library was developed to simplify Xposed module preference access. XSharedPreferences has been known to silently fail on some devices, and does not support remote write access or value changed listeners. Thus, RemotePreferences was born.

Of course, feel free to use this library anywhere you like; it's not limited to Xposed at all! :-)

How does it work?

To achieve true inter-process SharedPreferences access, all requests are proxied through a ContentProvider. Preference change callbacks are implemented using ContentObserver.

This solution does not use MODE_WORLD_WRITEABLE (which was deprecated in Android 4.2) or any other file permission hacks.

Running tests

Connect your Android device and run:

./gradlew :testapp:connectedAndroidTest

License

Distributed under the MIT License.

Changelog

0.8

  • RemotePreferences is now hosted on mavenCentral()
  • Fixed onSharedPreferenceChanged getting the wrong key when calling clear()

0.7

  • Added support for preferences located in device protected storage (thanks to Rijul-A)

0.6

  • Improved error checking
  • Fixed case where strict mode was not applying when editing multiple preferences
  • Added more documentation for library internals
  • Updated project to modern Android Studio layout

0.5

  • Ensure edits are atomic - either all or no edits succeed when committing
  • Minor performance improvement when adding/removing multiple keys

0.4

  • Fixed IllegalArgumentException being thrown instead of RemotePreferenceAccessException

0.3

  • Values can now be null again
  • Improved error checking if you are using the ContentProvider interface directly

0.2

  • Fixed catastrophic security bug allowing anyone to write to preferences
  • Added strict mode to distinguish between "cannot access provider" vs. "key doesn't exist"
  • Keys can no longer be null or "", values can no longer be null

0.1

  • Initial release.

remotepreferences's People

Contributors

apsun avatar rijul-a avatar yubyf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

remotepreferences's Issues

Bootloop on some device

I created an app with list of package that enable or disable feature.
When the module get called (I hook onCreate for all Application.class) it will use RemotePreference with context from the Application.
The problem occurs when com.android.systemui get loaded before my content provider start (it happen on some device) then the boot process keep waiting for the CP.

No exception thrown when Key is NULL

If RemotePreferences is called upon a nulled object reference,
such as:

SharedPreferences rpo = new RemotePreferences(context, "authority", "pref_name", true);
String prefKey;
String prefValue;

// <... code to set prefKey as some key that fails ...>
// At this point, prefKey = null

try {
    prefValue = rpo.getString(prefKey, "");
}
catch (RemotePreferenceAccessException e) {
    Log.e("FAIL");
}

Log.d(prefValue);

This above code fails silently.
The fail message does not show up, and the last line, Log.d(prefValue); does not even reach, but without any errors on the logcat.

I don't understand how to declare "context"

Hello,
I follow your guide to use RemotePreferences : my goal is to change a text color of Samsung Music, and I use your library to allow me to get the value returned by a colorpicker.

I succeed with SharedPreferences library to save my value and to recover them when I open my app, but now I don't arrived to recover this value with your library in my Module.java

I know it's not a bug but I don't understand by what I can declare your "context" variable.

SharedPreferences prefs = new RemotePreferences(context, "com.chacha.samsungmusiccustomiser", "main_prefs");
       value = prefs.getInt("MiniArtistColor", 0); 

I use this in my Module.java
Can you help me please ?
I'm sorry if there are mistakes I'm french

[QUESTION] How to get preferences from Android system package?

I'm trying to load the preferences from the Android package but the preferences are not read for this package.
You can see the code here - https://github.com/Firefds/FirefdsKit/blob/pie_provider/firefdskit/src/main/java/sb/firefds/pie/firefdskit/XAndroidPackage.java
https://github.com/Firefds/FirefdsKit/blob/pie_provider/firefdskit/src/main/java/sb/firefds/pie/firefdskit/XSystemWide.java

Is this the same reason why we shouldn't use RemotePreferences from within IXposedHookZygoteInit.initZygote?

Is there a workaround for android packages?

Unable to launch app **** for provider **** process is bad

Failed to find provider info for ****

frameworks/base/core/java/android/app/ActivityManagerService.java

`public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name) {
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}

    return getContentProviderImpl(caller, name);  
}  
private final ContentProviderHolder getContentProviderImpl(  
    IApplicationThread caller, String name) {  
    ContentProviderRecord cpr;  
    ProviderInfo cpi = null;  

    synchronized(this) {  
        ProcessRecord r = null;  
        if (caller != null) {  
            r = getRecordForAppLocked(caller);  
            if (r == null) {  
                throw new SecurityException(  
                        "Unable to find app for caller " + caller  
                      + " (pid=" + Binder.getCallingPid()  
                      + ") when getting content provider " + name);  
            }  
        }  

        // First check if this content provider has been published...

        cpr = mProvidersByName.get(name);  
        if (cpr != null) {  

...

        } else {  
            try {  
                cpi = AppGlobals.getPackageManager().  
                    resolveContentProvider(name,  
                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);  
            } catch (RemoteException ex) {  
            }  
            if (cpi == null) {  
                return null;  
            }  

            String msg;  
            if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) {  
                throw new SecurityException(msg);  
            }  

            if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate  
                    && !cpi.processName.equals("system")) {  
                // If this content provider does not run in the system

                // process, and the system is not yet ready to run other

                // processes, then fail fast instead of hanging.

                throw new IllegalArgumentException(  
                        "Attempt to launch content provider before system ready");  
            }  
              
            cpr = mProvidersByClass.get(cpi.name);  
            final boolean firstClass = cpr == null;  
            if (firstClass) {  
                try {  
                    ApplicationInfo ai =  
                        AppGlobals.getPackageManager().  
                            getApplicationInfo(  
                                    cpi.applicationInfo.packageName,  
                                    STOCK_PM_FLAGS);  
                    if (ai == null) {  
                        Slog.w(TAG, "No package info for content provider "  
                                + cpi.name);  
                        return null;  
                    }  
                    cpr = new ContentProviderRecord(cpi, ai);  
                } catch (RemoteException ex) {  
                    // pm is in same process, this will never happen.

                }  
            }  

            if (r != null && cpr.canRunHere(r)) {  
                // If this is a multiprocess provider, then just return its

                // info and allow the caller to instantiate it.  Only do

                // this if the provider is the same user as the caller's

                // process, or can run as root (so can be in any process).

                return cpr;  
            }  

            if (DEBUG_PROVIDER) {  
                RuntimeException e = new RuntimeException("here");  
                Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid  
                      + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);  
            }  

            // This is single process, and our app is now connecting to it.

            // See if we are already in the process of launching this

            // provider.

            final int N = mLaunchingProviders.size();  
            int i;  
            for (i=0; i<N; i++) {  
                if (mLaunchingProviders.get(i) == cpr) {  
                    break;  
                }  
            }  

            // If the provider is not already being launched, then get it

            // started.

            if (i >= N) {  
                final long origId = Binder.clearCallingIdentity();  
                ProcessRecord proc = startProcessLocked(cpi.processName,  
                        cpr.appInfo, false, 0, "content provider",  
                        new ComponentName(cpi.applicationInfo.packageName,  
                                cpi.name), false);  
                if (proc == null) {  
                    Slog.w(TAG, "Unable to launch app "  
                            + cpi.applicationInfo.packageName + "/"  
                            + cpi.applicationInfo.uid + " for provider "  
                            + name + ": process is bad");  
                    return null;  
                }  
                cpr.launchingApp = proc;  
                mLaunchingProviders.add(cpr);  
                Binder.restoreCallingIdentity(origId);  
            }  

            // Make sure the provider is published (the same provider class

            // may be published under multiple names).

            if (firstClass) {  
                mProvidersByClass.put(cpi.name, cpr);  
            }  
            mProvidersByName.put(name, cpr);  

            if (r != null) {  
                if (DEBUG_PROVIDER) Slog.v(TAG,  
                        "Adding provider requested by "  
                        + r.processName + " from process "  
                        + cpr.info.processName);  
                Integer cnt = r.conProviders.get(cpr);  
                if (cnt == null) {  
                    r.conProviders.put(cpr, new Integer(1));  
                } else {  
                    r.conProviders.put(cpr, new Integer(cnt.intValue()+1));  
                }  
                cpr.clients.add(r);  
            } else {  
                cpr.externals++;  
            }  
        }  
    }  

    // Wait for the provider to be published...

    synchronized (cpr) {  
        while (cpr.provider == null) {  
            if (cpr.launchingApp == null) {  
                Slog.w(TAG, "Unable to launch app "  
                        + cpi.applicationInfo.packageName + "/"  
                        + cpi.applicationInfo.uid + " for provider "  
                        + name + ": launching app became null");  
                EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,  
                        cpi.applicationInfo.packageName,  
                        cpi.applicationInfo.uid, name);  
                return null;  
            }  
            try {  
                cpr.wait();  
            } catch (InterruptedException ex) {  
            }  
        }  
    }  
    return cpr;  
}  `

Should checkAccess check for the preferences owner package?

Maybe I'm missing something obvious, but should I check whether the calling package is the preferences owner in checkAccess() in the RemotePreferenceProvider subclass to give it write access, or is write access automatically granted to the preferences owner even when checkAccess() always return false. Also, what are should I use to call getCallingPackage() from API 17, since that method is not available on that API. Keep the good work.

[Question] RemotePreferences not loaded after Android reboot

Hi,

I just applied your RemotePreference library to an Xposed module which needed to be adapted for Android 8.0.0.
After some trial and error it works fine, but for one thing: After an Android reboot it doesn't load the Preferences correctly in the part of the xposed module that should act on the settings.
I have to go into the Settings (gui part of SettingsFragment) again, "do something" and then it is OK again.

My github is here: https://github.com/hvdwolf/XSofiaTweaker
The only things actually important are the Settingsfragment.java and the XSofiaTweaker.java.

I'm a beginning java and beginning xposed programmer so I already assume I did something incorrect.
Note that the code still contains a lot of non-functional crap as I simply don't know how to get it working, but that is not my question.

multiple apps use the library but they have same authority for a content provider, which creates conflict

I have created an android library that generates a random UUID when a user launches an app integrated with this library. If a user already has the UUID, we store it in sharedpref.
Now I want to access the UUID to other apps that are integrated with my library.(within the same device). I don't want to create a new random UUID for every app on the same device.

Can you help me to solve it? @apsun

Unable to get provider

Hello, first of all, thanks you for your good work!

I just followed multiple times the installation guide, and I double-checked this by comparing to the testapp, I can't start my application with RemotePreferences because of a problem with provider.

In Manifest.xml:

<provider
android:authorities="com.myapp.test.preferences"
android:name=".MyPreferenceProvider"
android:exported="true" />

In Java/com.myapp.test folder, MyPreferenceProvider Class:

public class MyPreferenceProvider extends RemotePreferenceProvider {
public MyPreferenceProvider() {
super("com.myapp.test.preferences", new String[] {"test"});
}
}

And when I compile it:
java.lang.RuntimeException: Unable to get provider com.myapp.test.MyPreferenceProvider: java.lang.ClassNotFoundException: Didn't find class "com.myapp.test.MyPreferenceProvider" on path .... blablabla

I'm sure that's a easy fix but I can't find on internet a solution for this particular problem with your library.
If you need any other information, I can give it to you.
Thanks you for helping me and have a good day!

EDIT: I think it's comes from Xposed, i'm using the v90-beta3 and the first errors logs after ClassNotFoundException is at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:361)

Complete error:
2021-01-17 02:07:07.810 10188-10188/com.myapp.test E/AndroidRuntime: FATAL EXCEPTION: main Process: com.myapp.test, PID: 10188 java.lang.RuntimeException: Unable to get provider com.myapp.test.MyPreferenceProvider: java.lang.ClassNotFoundException: Didn't find class "com.myapp.test.MyPreferenceProvider" on path: DexPathList[[zip file "/data/app/com.myapp.test-uibVPddJ9zeWqq_LXlkdFg==/base.apk"],nativeLibraryDirectories=[/data/app/com.myapp.test-uibVPddJ9zeWqq_LXlkdFg==/lib/x86, /system/lib, /system/vendor/lib]] at android.app.ActivityThread.installProvider(ActivityThread.java:6288) at android.app.ActivityThread.installContentProviders(ActivityThread.java:5851) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5772) at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:361) at android.app.ActivityThread.handleBindApplication(<Xposed>) at android.app.ActivityThread.-wrap1(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1661) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:108) Caused by: java.lang.ClassNotFoundException: Didn't find class "com.testapp.test.MyPreferenceProvider" on path: DexPathList[[zip file "/data/app/com.testapp.test-uibVPddJ9zeWqq_LXlkdFg==/base.apk"],nativeLibraryDirectories=[/data/app/com.testapp.test-uibVPddJ9zeWqq_LXlkdFg==/lib/x86, /system/lib, /system/vendor/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93) at java.lang.ClassLoader.loadClass(ClassLoader.java:379) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at android.app.ActivityThread.installProvider(ActivityThread.java:6273) at android.app.ActivityThread.installContentProviders(ActivityThread.java:5851)  at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5772)  at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method)  at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:361)  at android.app.ActivityThread.handleBindApplication(<Xposed>)  at android.app.ActivityThread.-wrap1(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1661)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6541)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)  at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:108)  Suppressed: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/crossbowffs/remotepreferences/RemotePreferenceProvider; at java.lang.VMClassLoader.findLoadedClass(Native Method) at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:738) at java.lang.ClassLoader.loadClass(ClassLoader.java:363) ... 16 more Caused by: java.lang.ClassNotFoundException: Didn't find class "com.crossbowffs.remotepreferences.RemotePreferenceProvider" on path: DexPathList[[zip file "/data/app/com.testapp.test-uibVPddJ9zeWqq_LXlkdFg==/base.apk"],nativeLibraryDirectories=[/data/app/com.testapp.test-uibVPddJ9zeWqq_LXlkdFg==/lib/x86, /system/lib, /system/vendor/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93) at java.lang.ClassLoader.loadClass(ClassLoader.java:379) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) ... 19 more

Cannot get preferences when application get killed

I test a demo, it work great while app is running, which was configured contentProvider. But when I kill the app, RemotePreferences cannot ruturn correct preferences. If on strict mode, it will throw Exception:

Caused by: com.crossbowffs.remotepreferences.RemotePreferenceAccessException: query() failed or returned null cursor
        at com.crossbowffs.remotepreferences.RemotePreferences.query(RemotePreferences.java:190)
        at com.crossbowffs.remotepreferences.RemotePreferences.querySingle(RemotePreferences.java:233)
        at com.crossbowffs.remotepreferences.RemotePreferences.getInt(RemotePreferences.java:92)
...
Caused by: com.crossbowffs.remotepreferences.RemotePreferenceAccessException: java.lang.SecurityException: Isolated process not allowed to call getContentProvider
        at com.crossbowffs.remotepreferences.RemotePreferences.wrapException(RemotePreferences.java:169)
        at com.crossbowffs.remotepreferences.RemotePreferences.query(RemotePreferences.java:187)
        at com.crossbowffs.remotepreferences.RemotePreferences.querySingle(RemotePreferences.java:233)
        at com.crossbowffs.remotepreferences.RemotePreferences.getInt(RemotePreferences.java:92)

I'm using Android 8.0 Oreo, and I had try device encrypted preferences described on README.

Move away from jcenter

Options (in no particular order):

  1. Maven Central. Absolute dogshit UX (seriously, open a Jira ticket to create a repo?), but the "default" option for maven so it's probably too big to fail.
  2. JitPack.io. Looks pretty straightforward, I've seen some other projects use this as well.
  3. Self host. I don't think it's worth spending time and paying $$ for this.
  4. Since the maven protocol is just XML over HTTP, maybe just dump the jars on GitHub pages or a S3 bucket?

I'm going to wait until March to see if Google has some official solution (it would be ideal if they could start hosting their own public maven repo), if nothing changes by then I'll start migrating.

Does not work when trying to access via Xposed on an app targeting Android 11

As title, the library doesn't work when the app Xposed is injecting into targets Android 11, due to App Visibility changes.

Logcat shows this error:

E ActivityThread: Failed to find provider info for com.kieronquinn.app.darq.provider.remoteprefs

It works perfectly fine with apps not targeting 11. Examples I can reproduce on are LinkedIn (targets 11) and Snapchat (targets 10)

From research, this can be resolved by adding a <provider> to the <queries> tag in the target app's manifest, but obviously we don't have access to that so it can't be done. Might have to be done on boot by injecting into the server.

Is it Solve Xsharedpreference Can’t Access Preference XML

As we knw after SDK 25 we other app can't access preference XML file I have a module which hook param which use put in my module and that data store in user_prefs.XML but my module easily get data in SDK less than 24 and can't access greater than 24 so ? Is it solve ?this

[INFO] java.lang.SecurityException: Given calling package android does not match caller's uid

I don't know it's a real issue of RemotePreferences, I report for info to other users.
With Xposed and similar projects, it is not possible to have the Context of hooked application, thank to @MPeti1 and the info in issue #3 there was a good alternative for old versions of Android.

Context systemContext = (Context) XposedHelpers.callMethod( XposedHelpers.callStaticMethod( XposedHelpers.findClass("android.app.ActivityThread", loadPackageParam.classLoader), "currentActivityThread"), "getSystemContext" );

With this row we can get the context of package "android" and is good for create the object RemotePreferences.
With Android 8 and 8.1, the context "android" can query the Provider without exception.
I'm testing an old module which use RemotePreferences on Android 10 (LineageOS 17.1) and LSPosed, but everytime my module from handleLoadPackage try to query the provider I got this exception:


java.lang.SecurityException: Given calling package android does not match caller's uid 10161
 	at android.os.Parcel.createException(Parcel.java:2071)
 	at android.os.Parcel.readException(Parcel.java:2039)
 	at android.os.Parcel.readException(Parcel.java:1987)
 	at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:5056)
 	at android.app.ActivityThread.acquireProvider(ActivityThread.java:6561)
 	at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2725)
 	at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:2117)
 	at android.content.ContentResolver.query(ContentResolver.java:928)
 	at android.content.ContentResolver.query(ContentResolver.java:880)
 	at android.content.ContentResolver.query(ContentResolver.java:836)
 	at com.crossbowffs.remotepreferences.RemotePreferences.query(RemotePreferences.java:214)
 	at com.crossbowffs.remotepreferences.RemotePreferences.querySingle(RemotePreferences.java:263)
 	at com.crossbowffs.remotepreferences.RemotePreferences.getBoolean(RemotePreferences.java:135)

I tried to set strictmode to true without success, I tried the solution in issue #12 setExecutable(true, false) and setReadable(true, false) without success.
Android check the name of package in context ("android") and the uid of caller (my hooked application) and with mismatch throw an exception.

So I think this project is useless with *Posed and new Android if this check can't be disabled.

From Readme:
"This library was developed to simplify Xposed module preference access. "
In the past sure, now not more.

Exception thrown when accessing preferences from Xposed (Android 11)

When using RemotePreferences on Xposed handleLoadPackage function,
using the below code, exception is thrown.
Therefore, the preferences are not being read correctly when it is called from a different uid.

Configuration is
Device: POCO Phone F1
Android Version: Android 11 (crDroid 7.1)
XPosed: EdXposed Canary (For Android 11, SandHook)

Exception:
java.lang.SecurityException: Given calling package android does not match called's uid 10362

Code:

Context context = (Context) XposedHelpers.callMethod(activityThread, "getSystemContext");
pref = new RemotePreferences(context, "com.defyworks.xposed.spoofr.preferences", "main_prefs", true);

try {
	Boolean value = pref.getBoolean(lpp.packageName , false);
	LogManager.writeDebug("Pref Value for [" + lpp.packageName + "] is set " + value);
} catch (RemotePreferenceAccessException e) {
	LogManager.writeError("Could not read pref for [" + lpp.packageName + "]");
	LogManager.writeError("Reason for Error: \n" + e.getCause().toString());
}

getting context in handleLoadPackage

Hi!
You wrote we should load preferences in IXposedHookLoadPackage.handleLoadPackage. But how do one get a context here? AndroidAppHelper.currentApplication().getApplicationContext() will return null since there is no context before handleBindApplication(), because it'll be set up in it.

Doesn't work in initZygote

Hi, I know it says in the readme that it doesn't work in initZygote, but what if I need it there? I noticed that it can create a new instance of my shared preferences without problem in initZygote, but it fails at getting any preferences UNTIL I open my app. After that it works as expected (any changes are reflected in the hooked process). Is there a way to make it work without having to manually open the app every time I reboot the phone?

App closed when try to use RemotePreference

my app force closed

i add this in mainfest

<provider android:name=".ProviderPreference" android:authorities="com.androidx.faux.preference" android:exported="true" />

this is remote preference class

`public class ProviderPreference extends RemotePreferenceProvider {

public ProviderPreference() {
    super("com.androidx.faux.preferences", new String[] {"user_prefs"});
}

}`

this xposed hooked class

` @OverRide
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
SharedPreferences sharedPreferences = new RemotePreferences(context, "com.androidx.faux.preference", "user_prefs");

    if (!lpparam.packageName.equals("com.androidx.faux")) {
        XsharedPreference.reload();
        IMEI.load(lpparam);
        AndroidID.load(lpparam);
        Bmac.load(lpparam);
    }

`

please help

Android 10 return default value

Hello, apsun.
I have problem with my module that can't return new value in Android 10
Do you have any trick or tips to android 10?
It always return default value

Android 13:RemotePreferenceAccessException: query() failed or returned null cursor

Error Message :

2022-07-17 01:32:38.286 1646-3403/? W/WakePathChecker: MIUILOG-AutoStart, Service/Provider/Broadcast Reject userId= 0 caller= com.eg.android.******** callee= com.example.fuck*** classname=com.example.fuck***.utils.MyPreferenceProvider action=null wakeType=4
2022-07-17 01:32:38.286 15540-15540/? E/ActivityThread: Failed to find provider info for com.example.fuck***preferences
2022-07-17 01:32:38.287 15540-15540/? E/LSPosed-Bridge: com.crossbowffs.remotepreferences.RemotePreferenceAccessException: query() failed or returned null cursor
        at com.crossbowffs.remotepreferences.RemotePreferences.query(RemotePreferences.java:214)
        at com.crossbowffs.remotepreferences.RemotePreferences.queryAll(RemotePreferences.java:290)
        at com.crossbowffs.remotepreferences.RemotePreferences.getAll(RemotePreferences.java:97)
        at com.example.fuck***.HookCore$1.afterHookedMethod(HookCore.java:54)
        at de.robv.android.xposed.XposedBridge$AdditionalHookInfo.callback(Unknown Source:147)
        at LSPHooker_.attachBaseContext(Unknown Source:11)
        at com.***.mobile.***.LauncherApplication.attachBaseContext(LauncherApplication.java:100008)
        at android.app.Application.attach(Application.java:333)
        at android.app.Instrumentation.newApplication(Instrumentation.java:1178)
        at android.app.LoadedApk.makeApplication(LoadedApk.java:1369)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7052)
        at android.app.ActivityThread.access$1600(ActivityThread.java:276)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2131)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:210)
        at android.os.Looper.loop(Looper.java:299)
        at android.app.ActivityThread.main(ActivityThread.java:8291)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)

AndroidManifest.xml Code:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fuck***">

    <queries>
        <provider android:authorities="${applicationId}.preferences" />
    </queries>

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:requestLegacyExternalStorage="true">

...

        <provider
            android:name=".utils.MyPreferenceProvider"
            android:authorities="${applicationId}.preferences"
            android:enabled="true"
            android:exported="true" />
    </application>
</manifest>

Xposed Hook Code:

  @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        if (!"com.android.****".equals(lpparam.packageName)) {
            return;
        }

        XposedHelpers.findAndHookMethod(ContextWrapper.class, "attachBaseContext", Context.class, new XC_MethodHook() {
            protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) {
                Context context = (Context) param.args[0];
                RemotePreferences prefs = new RemotePreferences(context, Const.PROVIDER_AUTHORITIES, Const.PREFERENCE_FILE_NAME, true);

                // getString() is null, not work.
                XposedBridge.log("[xxx] read-conf CHECK_TIME:" + prefs.getString(Const.CHECK_TIME, "null"));
            }
        });
        XposedHelpers.findAndHookMethod(Activity.class, "onResume", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                Context context = (Activity) param.thisObject;
                RemotePreferences prefs = new RemotePreferences(context, Const.PROVIDER_AUTHORITIES, Const.PREFERENCE_FILE_NAME, true);

                   // getString() is null, not work.
                XposedBridge.log("[xxx] read-conf CHECK_TIME1:" + prefs.getString(Const.CHECK_TIME, "null"));
            }
        });
    }

Variable preference name?

My app has sharedpreferences of variable count and names, how can I add them all to MyPreferenceProvider? Since super(...) must be on the first line of the constructor, I cannot create a variable string array as parameter.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.