[Q][Development] XSharedPreferences issue, no entries

Search This thread

P1nGu1n_

Senior Member
Feb 13, 2013
979
2,567
For my Xposed Module Play Store Chagenlog an update was released yesterday, this added a GUI as wel as some options. There have been quite a few reports about settings preferences not being applied. After some debugging, I found out that this XSharedPreferences simply doesn't have any entries and thus always returns the default values. I'm 100% sure the options are set (the preferences screen shows them correct and you can see them in the .xml) and the right file is being loaded. There are no errors in the Xposed Log or in the logcat.

I've found a workaround (only tested by me), unchecking and re-checking an option and then the preferences are read correctly. All my modules (actually most of all Xposed Modules) use this way to load an user's preferences, I have absolutely no clue what's causing this behaviour.

The source code is on GitHub, links to relevant files:

For debugging purposes, I've added a snippet to dump the preferences beneath initializing XSharedPreferences. This says it loads the right file, the file exists but it contains no entries (size 0). So when trying to get values (getString, getBoolean etc), it only returns the default values.
Java:
sharedPreferences = new XSharedPreferences(BuildConfig.APPLICATION_ID);

XposedBridge.log(LOG_TAG + sharedPreferences.getFile().getAbsolutePath() + " exists: " + sharedPreferences.getFile().exists());
XposedBridge.log(LOG_TAG + " ---PREFS: " + sharedPreferences.getAll().size() + "---");
Map<String, ?> sortedKeys = new TreeMap<String, Object>(sharedPreferences.getAll());
for (Map.Entry<String, ?> entry : sortedKeys.entrySet()) {
    XposedBridge.log(LOG_TAG + entry.getKey() + "=" + entry.getValue().toString());
}

Summary
The app uses a PreferenceFragment to set the preferences and XSharedPreferences to load them. The changes are written to the .xml file and shown in the GUI. The XSharedPreferences instance remains empty and does not contain any entries, thus it always returns the default value. I don't get why it doesn't work, I don't even get why the 'workaround' does work.


I'd really appreciate any help, I'm stuck on this one. No idea what causes it and whether it's a but in my code or something else.
I hope I gave enough information. Thanks in advance. :)
 
Last edited:
  • Like
Reactions: CHEF-KOCH

GermainZ

Inactive Recognized Developer / Retired Forum Mod
Aug 3, 2012
6,170
8,805
Could something like `sharedPreferences.makeWorldReadable();` (probably needs to be in initZygote) solve your issue? I can't personally think of any reason this might happen except a permission issue.

(Also make sure you're using the latest Xposed Bridge API. I remember there were some commits related to XSharedPreferences, although I can't remember what they were exactly and can't check right now.)
 
  • Like
Reactions: P1nGu1n_

defim

Senior Member
Feb 18, 2012
2,744
1,489
Motorola Defy
Nexus 7 (2013)
Permission problem sounds reasonable. PSC has for its xml file only set 660, so world readable is mission. After changing it by command line Play Store starts as expected. But i've to say that i use in no app the makeWorldReadable(), Xposed should do it by itself: http://xdaforums.com/showpost.php?p=41976845&postcount=1586 But I also dont use settings fragment, which could cause it...
 
  • Like
Reactions: P1nGu1n_

P1nGu1n_

Senior Member
Feb 13, 2013
979
2,567
Could something like `sharedPreferences.makeWorldReadable();` (probably needs to be in initZygote) solve your issue? I can't personally think of any reason this might happen except a permission issue.

(Also make sure you're using the latest Xposed Bridge API. I remember there were some commits related to XSharedPreferences, although I can't remember what they were exactly and can't check right now.)

Permission problem sounds reasonable. PSC has for its xml file only set 660, so world readable is mission. After changing it by command line Play Store starts as expected. But i've to say that i use in no app the makeWorldReadable(), Xposed should do it by itself: http://xdaforums.com/showpost.php?p=41976845&postcount=1586 But I also dont use settings fragment, which could cause it...

First of al, both thanks you for your response, it's highly appreciated.

I've been testing with permissions, it indeed looks like a permission problem, because makeWorldReadable() solved it. I use the following line the SettingsFragment to make it World Readable, which has always worked, even though Context.MODE_WORLD_READABLE is officially deprecated because if security reasons:
Java:
getPreferenceManager().setSharedPreferencesMode(Context.MODE_WORLD_READABLE);

It creates a file with 660 permissions, with makeWorldReadable in initZygote it sets it to 664. This is my initZygote:
Java:
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
    sharedPreferences = new XSharedPreferences(BuildConfig.APPLICATION_ID);
    XposedBridge.log(LOG_TAG + "Readable before: " + sharedPreferences.getFile().canRead());
    sharedPreferences.makeWorldReadable();
    XposedBridge.log(LOG_TAG + "Readable after: " + sharedPreferences.getFile().canRead());
}

The weird thing is, both readable before and after return true, which indicates it has the permission to read the file before makeWorldReadable(). But... it doesn't work without it :confused:

In the end, I created a snippet in SettingsFragment to solve it where the problem arises, instead of makeWorldReadable():
Code:
File sharedPrefsDir = new File(getActivity().getFilesDir(), "../shared_prefs");
File sharedPrefsFile = new File(sharedPrefsDir, getPreferenceManager().getSharedPreferencesName() + ".xml");
if (sharedPrefsFile.exists()) {
    sharedPrefsFile.setReadable(true, false);
}

This still needs setSharedPreferencesMode(Context.MODE_WORLD_READABLE), otherwise the permissions will be reset to 660 when a preference changes, now they stay 664. So basically al it does it make it readable for others in addition to the setSharedPreferenceMode().

Thanks again for your replies, it really helped. I still think it's weird, especially since File.canRead() returns true, while it obviously can't read it. I hope it'll help others in the future.
 
  • Like
Reactions: kslakhani

MohammadAG

Inactive Recognized Developer
Sep 7, 2009
1,080
5,504
30
Jerusalem
mohammadag.xceleo.org
I think I use the deprecated SettingsActivity for this reason. I can override getSharedPreferences so it always returns a world readable file, this avoids the permissions resetting when a preference changes.

Sent from my HTC One_M8 using Tapatalk
 
  • Like
Reactions: P1nGu1n_

P1nGu1n_

Senior Member
Feb 13, 2013
979
2,567
I think I use the deprecated SettingsActivity for this reason. I can override getSharedPreferences so it always returns a world readable file, this avoids the permissions resetting when a preference changes.

Sent from my HTC One_M8 using Tapatalk

Thanks for your response, just checked out one of your modules, saw you were using getPreferenceManager().setSharedPreferencesMode(MODE_WORLD_READABLE); too. (and indeed SettingsActivity). This has always been sufficient for me using PreferenceFragment. To be sure it's world readable I now manually set the permissions on onPause as a workaround. Still weird because it has always worked flawless for me.
 

MohammadAG

Inactive Recognized Developer
Sep 7, 2009
1,080
5,504
30
Jerusalem
mohammadag.xceleo.org
Thanks for your response, just checked out one of your modules, saw you were using getPreferenceManager().setSharedPreferencesMode(MODE_WORLD_READABLE); too. (and indeed SettingsActivity). This has always been sufficient for me using PreferenceFragment. To be sure it's world readable I now manually set the permissions on onPause as a workaround. Still weird because it has always worked flawless for me.

Yeah, I also override getSharedPreferences in PreferenceActivity, that allows it to stay world readable.

Sent from my HTC One_M8 using Tapatalk
 

M66B

Recognized Developer
Aug 1, 2010
26,751
57,997
Be aware that using XSharedPreferences will probably lead to problems on Lollipop caused by more stringent SELinux rules.
 
  • Like
Reactions: P1nGu1n_

P1nGu1n_

Senior Member
Feb 13, 2013
979
2,567
Be aware that using XSharedPreferences will probably lead to problems on Lollipop caused by more stringent SELinux rules.
Good point, but it's too early to say. I'll wait for Xposed to be compatible (hope it will), than I'll look into what changes it'll require. That's something almost every Xposed developer will face ;p

Sent from my phone, please forgive any tpyos.
 

pyler

Senior Member
Jan 13, 2013
1,279
2,372
Breaking XSharedPreferences means that *almost* every module is not going to work on Lollipop.
 

pyler

Senior Member
Jan 13, 2013
1,279
2,372
I also migrated my project to use PreferenceFragment and getPreferenceManager().setSharedPreferencesMode(Context.MODE_WORLD_READABLE) pretty much does nothing. After I change any setting, prefs file lose "world available" mode.
 

asdfasdfvful

Senior Member
Apr 21, 2013
2,976
3,851
Montreal
allanwang.ca
I checked out P1ngu1n_'s implementation using PreferenceFragment, but it still doesn't work for me. Do any of you have an idea why?

Here is my source

The only difference I can see is that I don't have an xml file for the preferences and that I'm adding the keys in the fragment.

I even checked the permissions and they seem to be fine.
 
Last edited:

P1nGu1n_

Senior Member
Feb 13, 2013
979
2,567
I checked out P1ngu1n_'s implementation using PreferenceFragment, but it still doesn't work for me. Do any of you have an idea why?

Here is my source

The only difference I can see is that I don't have an xml file for the preferences and that I'm adding the keys in the fragment.

I even checked the permissions and they seem to be fine.

If the permissions seem to be fine, than what doesn't work?
 

Top Liked Posts

  • There are no posts matching your filters.
  • 1
    For my Xposed Module Play Store Chagenlog an update was released yesterday, this added a GUI as wel as some options. There have been quite a few reports about settings preferences not being applied. After some debugging, I found out that this XSharedPreferences simply doesn't have any entries and thus always returns the default values. I'm 100% sure the options are set (the preferences screen shows them correct and you can see them in the .xml) and the right file is being loaded. There are no errors in the Xposed Log or in the logcat.

    I've found a workaround (only tested by me), unchecking and re-checking an option and then the preferences are read correctly. All my modules (actually most of all Xposed Modules) use this way to load an user's preferences, I have absolutely no clue what's causing this behaviour.

    The source code is on GitHub, links to relevant files:

    For debugging purposes, I've added a snippet to dump the preferences beneath initializing XSharedPreferences. This says it loads the right file, the file exists but it contains no entries (size 0). So when trying to get values (getString, getBoolean etc), it only returns the default values.
    Java:
    sharedPreferences = new XSharedPreferences(BuildConfig.APPLICATION_ID);
    
    XposedBridge.log(LOG_TAG + sharedPreferences.getFile().getAbsolutePath() + " exists: " + sharedPreferences.getFile().exists());
    XposedBridge.log(LOG_TAG + " ---PREFS: " + sharedPreferences.getAll().size() + "---");
    Map<String, ?> sortedKeys = new TreeMap<String, Object>(sharedPreferences.getAll());
    for (Map.Entry<String, ?> entry : sortedKeys.entrySet()) {
        XposedBridge.log(LOG_TAG + entry.getKey() + "=" + entry.getValue().toString());
    }

    Summary
    The app uses a PreferenceFragment to set the preferences and XSharedPreferences to load them. The changes are written to the .xml file and shown in the GUI. The XSharedPreferences instance remains empty and does not contain any entries, thus it always returns the default value. I don't get why it doesn't work, I don't even get why the 'workaround' does work.


    I'd really appreciate any help, I'm stuck on this one. No idea what causes it and whether it's a but in my code or something else.
    I hope I gave enough information. Thanks in advance. :)
    1
    Could something like `sharedPreferences.makeWorldReadable();` (probably needs to be in initZygote) solve your issue? I can't personally think of any reason this might happen except a permission issue.

    (Also make sure you're using the latest Xposed Bridge API. I remember there were some commits related to XSharedPreferences, although I can't remember what they were exactly and can't check right now.)
    1
    Permission problem sounds reasonable. PSC has for its xml file only set 660, so world readable is mission. After changing it by command line Play Store starts as expected. But i've to say that i use in no app the makeWorldReadable(), Xposed should do it by itself: http://xdaforums.com/showpost.php?p=41976845&postcount=1586 But I also dont use settings fragment, which could cause it...
    1
    Could something like `sharedPreferences.makeWorldReadable();` (probably needs to be in initZygote) solve your issue? I can't personally think of any reason this might happen except a permission issue.

    (Also make sure you're using the latest Xposed Bridge API. I remember there were some commits related to XSharedPreferences, although I can't remember what they were exactly and can't check right now.)

    Permission problem sounds reasonable. PSC has for its xml file only set 660, so world readable is mission. After changing it by command line Play Store starts as expected. But i've to say that i use in no app the makeWorldReadable(), Xposed should do it by itself: http://xdaforums.com/showpost.php?p=41976845&postcount=1586 But I also dont use settings fragment, which could cause it...

    First of al, both thanks you for your response, it's highly appreciated.

    I've been testing with permissions, it indeed looks like a permission problem, because makeWorldReadable() solved it. I use the following line the SettingsFragment to make it World Readable, which has always worked, even though Context.MODE_WORLD_READABLE is officially deprecated because if security reasons:
    Java:
    getPreferenceManager().setSharedPreferencesMode(Context.MODE_WORLD_READABLE);

    It creates a file with 660 permissions, with makeWorldReadable in initZygote it sets it to 664. This is my initZygote:
    Java:
    @Override
    public void initZygote(StartupParam startupParam) throws Throwable {
        sharedPreferences = new XSharedPreferences(BuildConfig.APPLICATION_ID);
        XposedBridge.log(LOG_TAG + "Readable before: " + sharedPreferences.getFile().canRead());
        sharedPreferences.makeWorldReadable();
        XposedBridge.log(LOG_TAG + "Readable after: " + sharedPreferences.getFile().canRead());
    }

    The weird thing is, both readable before and after return true, which indicates it has the permission to read the file before makeWorldReadable(). But... it doesn't work without it :confused:

    In the end, I created a snippet in SettingsFragment to solve it where the problem arises, instead of makeWorldReadable():
    Code:
    File sharedPrefsDir = new File(getActivity().getFilesDir(), "../shared_prefs");
    File sharedPrefsFile = new File(sharedPrefsDir, getPreferenceManager().getSharedPreferencesName() + ".xml");
    if (sharedPrefsFile.exists()) {
        sharedPrefsFile.setReadable(true, false);
    }

    This still needs setSharedPreferencesMode(Context.MODE_WORLD_READABLE), otherwise the permissions will be reset to 660 when a preference changes, now they stay 664. So basically al it does it make it readable for others in addition to the setSharedPreferenceMode().

    Thanks again for your replies, it really helped. I still think it's weird, especially since File.canRead() returns true, while it obviously can't read it. I hope it'll help others in the future.
    1
    I think I use the deprecated SettingsActivity for this reason. I can override getSharedPreferences so it always returns a world readable file, this avoids the permissions resetting when a preference changes.

    Sent from my HTC One_M8 using Tapatalk