Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Access to Android Data folder?

29 views
Skip to first unread message

Andy Burnelli

unread,
Nov 20, 2022, 9:21:56 PM11/20/22
to
flibbertigibbet wrote:

> Sorted. FV File Pro does the job nicely.

I never see poorly written programs such as that "FV File Pro" program
for a few reasons, not the least of which is it includes Google spyware.

While I have eight file managers installed which do NOT incorporate
Google spyware into them, each of those eight was added because it
did something (long since forgotten by me) that the others didn't do.

But I'm always willing to learn about and use an app that does something
that others apps don't do as easily or as well or as fast, or whatever.

While these four file managers did NOT read my root partition just now.
No = Simple Mobile Tools File Manager
<https://play.google.com/store/apps/details?id=com.simplemobiletools.filemanager>
No = Samsung My Files File Manager App
<https://play.google.com/store/apps/details?id=com.sec.android.app.myfiles>
No = Files File Manager App Shortcut
<https://play.google.com/store/apps/details?id=org.aospstudio.files>
No = Amaze File Manager App
<https://play.google.com/store/apps/details?id=com.amaze.filemanager>

All of these read my root file system partition without issues.
Yes = X-plore File Manager App
<https://play.google.com/store/apps/details?id=com.lonelycatgames.Xplore>
Yes = MK Explorer File Manager App
<https://play.google.com/store/apps/details?id=pl.mkexplorer.kormateusz>
Yes = MiX File Manager App (the free version com.mixexplorer not on Google Play)
<https://mixplorer.com/>
<https://forum.xda-developers.com/t/app-2-2-mixplorer-v6-x-released-fully-featured-file-manager.1523691/#post-23109280>
Yes = FX File Manager App
<https://play.google.com/store/apps/details?id=nextapp.fx>

Any idea what FV File Manager does that those below don't do?
<https://play.google.com/store/apps/details?id=com.folderv.file>

If it doesn't do anything that the other file managers do, then I would
ask why you let Google spyware onto your phone without a good reason.
--
Posted out of the goodness of my heart to disseminate useful information
which, in this case, is to learn more about what FV File Manager can do.

Andy Burnelli

unread,
Nov 20, 2022, 9:23:42 PM11/20/22
to
flibbertigibbet wrote:

>>If it doesn't do anything that the other file managers do, then I would
>>ask why you let Google spyware onto your phone without a good reason.
>
> I don't know what you mean by Google spyware, and I cannot see how what
> seems like a reputable file manager costing more than L5 can be malicious.
> If you think I'm better off not having it on my devices then I'll remove it
> and get my fiver back before my cooling off time runs out. Thanks.

There are many others who know far more than I do about GSF processes.
<https://i.postimg.cc/mk2CKQdn/gsfid09.jpg> GSF services on Android

But why do you think trusted developers go to the trouble to add a filter
to the replacement Google Play Store clients which expressly filters out
permanently any and all apps on the Google Play Store with GSF in them?
<https://i.postimg.cc/YStB48LH/gsfid03.jpg> Filter out GSF apps

Why do you think trusted developers go to the trouble to create methods for
a normal (non rooted) knowledgeable user to view the GSF ID at will?
<https://i.postimg.cc/G2Cz4GHz/gsfid04.jpg> Evozi Device ID reports GSF ID

And, why do you think they write tools to _change_ that unique GSF ID?
<https://i.postimg.cc/X7ZspnsG/gsfid01.jpg> You can change your GSF ID

Much like knowledgeable users can change & now delete their advertising ID.
<https://i.postimg.cc/nhNNQvNN/adid07.jpg> Check Advertising ID
<https://i.postimg.cc/q77fJVdR/adid05.jpg> Reset Advertising ID
<https://i.postimg.cc/XvqM5CSd/adid06.jpg> Delete Advertising ID

My main beef with mobile phone users is most are like sheep led to
slaughter, when it comes to THINKING for themselves about what they are
doing. Instead, I wish people would _think_ when they install Android apps.
<https://i.postimg.cc/G2QP0CFz/aurora15.jpg> FOSS Google Play Store client

MARKETING organizations made it easy to be led to slaughter by the nose.
It's our job to be wary when MARKETING hooks that ring into our noses.

The Google Play Store client is a nose ring MARKETING hooks into our noses.

Personally, from the moment I set up a phone, I disable the default Google
Play Store client & use FOSS replacement Google Play Store clients instead.
<https://i.postimg.cc/CL9GpzVc/aurora01.jpg> FOSS Google Play Store client

These FOSS Google Play Store clients have options MARKETING won't give you.
<https://i.postimg.cc/PrvDyT8Y/aurora03.jpg> Spoof hardware & geolocation

An example is they auto-save all APKs for you whenever you install apps!
<https://i.postimg.cc/Z5kdD2rg/aurora04.jpg> Choose where to download APKs

And, these Google Play Store clients work WITHOUT you needing an account.
<https://i.postimg.cc/NG5pHyBx/aurora10.jpg> No need for a Google Account

For some reason, Google MARKETING doesn't give you those options in the
default Google Play Store client; but the FOSS replacement clients do.

But better yet, they have options to help maintain your privacy from GSF.

In fact, if you use the Google Play Store client to the Google Play Store
repository, you can't easily see which apps contain the Google spyware.

But if you use the FOSS Google Play Store clients to the Google Play Store
repository, they make it VERY CLEAR which apps contain GSF Google spyware.
<https://i.postimg.cc/RF06HBB3/aurora05.jpg> Basic filters for software

Notice in that screenshot there are only apps which do not use GSF code.
<https://i.postimg.cc/P5YYKT3H/aurora14.jpg> Filter out apps linked to GSF

In order of priority as shown in those Google Play Store client filters:
1. Filter out GSF dependent apps (usually apps with gsf are not allowed)
2. Filter out payware apps (usually payware apps are not allowed to show)
3. Filter out apps with ads (usually apps with ads are not allowed to show)
4. Filter based on ratings (usually 4+ and above is allowed to show)
5. Filter based on number of downloads (usually 1M+ is allowed to show)

Why do you think there are only five app filters with GSF being the first?
<https://i.postimg.cc/7PdGfdQ6/aurora08.jpg> Some filters are not common

Why do you think people go to trouble to change the unique Android GSF ID?
<https://i.postimg.cc/YStB48LH/gsfid03.jpg> Filter out GSF apps

Run a quick search for any of these keywords and let us know what you find.
A. com.google.android.gsf (package)
B. Google Services Framework (APK)
C. com.google.process.gapps (process)

In summary, I consider Google Services Framework to be Google spyware which
less reputable developers tend to link into their Android app source code.

Having said that, I'm sure there are many others (e.g., Andy Burns for one)
who know far more about this pernicious Google spyware than I do, so I
welcome people who know far more than I do to help answer your questions.

In short, if the app you found links in Google Services Framework, and if
it's the _only_ app on the planet that does what you need, then I'd use
that app (if I must); but, conversely, if there are plenty of well written
apps which do NOT link in Google GSF spyware, then I'd use them instead.

It's a simple decision for me, especially as my Google Play Store client
never shows me those poorly written apps in the first place when I search.
<https://i.postimg.cc/RF06HBB3/aurora05.jpg> Filters Google won't give you
--
Posted out of the goodness of my heart to disseminate useful information
which, in this case is to explain why I avoid apps with GSF linked in them.

Andy Burnelli

unread,
Nov 20, 2022, 9:24:42 PM11/20/22
to
flibbertigibbet wrote:

> Up until quite recently I've been using
> File Manager Plus https://bit.ly/3Vb0h31
> and or
> USB Media Explorer https://bit.ly/3EM2wEx
> to get around my Galaxy S22 Ultra, because the standard file explorer is
> pretty basic and had been giving me the runaround when trying to access my
> Data folder. Now, though, since updating to Android 13 these paid-for
> 3rd-party apps won't give me access to that folder. Can anyone here tell me
> how I can get these apps to cooperate with me, or maybe tell me which app
> bypasses Android's efforts to keep their customers out of this folder,
> please?

I just made these screenshots for you out of the goodness of my soul.

<https://i.postimg.cc/fT7MSr90/root01.jpg> Even with All Files Access=On
<https://i.postimg.cc/05wkPQ5n/root02.jpg> Half of file managers read root
<https://i.postimg.cc/R0hm8Cbc/root03.jpg> & half of file managers do not

I'm not sure if this is a troll or not, but if I assume it's a sincere
question, then I'm glad to pitch in to purposefully helpfully help out.

I've been successful reading almost the entire Android file system using
a variety of common methods (without being rooted) but some file managers
do _not_ read the root file system as shown by my screenshots below.

Even when you give the file manager "All Files Access = On" permission,
half of the free file managers still don't seem to show root files.
Yes = MK Explorer File Manager App
<https://play.google.com/store/apps/details?id=pl.mkexplorer.kormateusz>
Yes = MiX File Manager App
When I was researching this for you, I found there is also "Usage Data Access"
which needed to be granted for _some_ of the apps above.

I'm not sure if that's the reason half of the file managers could read
the root partition and the other half could not. Maybe others who know
far more about Android than I ever will know can tell us if it matters.

To be clear, my Android phone is still owned by T-Mobile & is not rooted.
Also note that adb on Windows can read the root partition over Wi-Fi too.
C:\> adb devices
That should report the devices that adb is connected to, for example:
List of devices attached
192.168.0.2:54321 device

C:\> adb shell netstat
That should list the phone's TCP/IP connectivity tables.

C:\> adb shell service list
That should list all the running services on the phone.

C:\> adb shell ps
That should list all the running processes on the phone.

C:\> adb shell ifconfig
That should provide your Android network interface information.

C:\> adb shell "cd /sdcard/Download && ls"
That should list files in your internal storage Download folder.

C:\> adb shell "cd /sdcard && mkdir temp"
That should create a "temp" directory in your internal
storage sdcard on your Android phone.

C:\> adb shell screencap -p /sdcard/temp/screenshot.png
That should snap a screenshot of your android phone & store it
in the newly created temp folder on the Android phone.

C:\> adb shell screenrecord /sdcard/temp/screenrecord.mp4
Do whatever on the Android phone & then press Ctrl+C to end.
That should create an MP4 recording of your Android screen.

C:\> adb install "C:\path-to\filename.apk"
That should install the APK from Windows over Wi-Fi onto Android.
(Note this is useful when you have hundreds of apps like I do!)
<https://i.postimg.cc/bN875p8b/apk01.jpg> Windows APK archive

C:\> adb push "C:\path-to\filename.apk" /sdcard/Download
That should copy the named file from Windows to Android &
(in this case) put it in your internal storage "Download" folder.

Note that each phone OEM "can" use a different filespec for
internal & external sdcards (e.g., /storage/emulated/0/Download).

C:\> adb push C:\path\apk_archive\ /sdcard/Download/apks
That should create a folder named "apks" in the Android phone's
internal storage "Download" folder and then copy all the files
from the Windows "apk_archive" folder into that new "apks" folder.

C:\> adb shell
$ /storage/emulated/0/DCIM
$ ls
$ exit
That should allow you to interactively manage the Android
filesystem from Windows over Wi-Fi. Note these are common:
/mnt/sdcard/DCIM
/sdcard/DCIM
/sdcard/DCIM

C:\> adb logcat
Use this if you're a glutton for punishment as it will forever
spit out a log of what's going on your phone (until you Ctrl+C).

C:\> adb logcat *:E
The values are:
V: Verbose (lowest priority)
D: Debug
I: Info
W: Warning
E: Error
F: Fatal
S: Silent (highest priority. Nothing is printed)
Note logcat has multiple options, e.g.,
adb logcat Tag1:I *:S
That will list output log messages with the tag "Tag1"
and priority level Info or higher.
The *:S at the end will exclude the log from other tags
with any priority.

C:\> adb shell getprop | FindStr /i "ro.build.version"
Get properties off the phone & grep for the given keyword.

C:\> adb shell getprop ro.build.version.security_patch
This will report the property of the security patch level.

C:\> adb shell getprop ro.build.fingerprint
This will report basic hardware information about your phone.

C:\> adb shell input swipe 500 1000 500 100
This will instantly swipe from center to the top of the screen.

You can add a time period, e.g., take 3 seconds to swipe that.
C:\> adb shell input swipe 500 1000 500 100 3000

C:\> adb shell input text "K-9\ Mail"
This will enter into the phone's search GUI a search for that app.

C:\> adb shell pm list packages
That should list all the packages installed on your Android phone.

C:\> adb shell pm list packages | findStr /i "facebook"
That should list all the packages with that string in their name.

C:\> adb shell pm path com.facebook.appmanager
That should list the path to the named package, e.g.,
package:/system/app/FBAppManager_NS/FBAppManager_NS.apk

C:\> adb pull /system/app/FBAppManager_NS/FBAppManager_NS.apk
That should copy the APK from Android over to Windows.

C:\> adb shell dumpsys package com.facebook.appmanager
This should list an app's components, activities & services, etc.

C:\> adb shell pm list permissions | FindStr facebook
This should list all permissions granted for that particular app.

C:\> adb shell pm revoke com.facebook.appmanager android.permission.READ_EXTERNAL_STORAGE
This should revoke the stated permissions from that app.

C:\> adb shell pm grant com.facebook.appmanager android.permission.READ_EXTERNAL_STORAGE
This should grant the stated permissions to that app.

C:\> adb shell pm clear com.facebook.appmanager
This should clear all the application data in that package.

C:\> adb shell pm uninstall -k --user 0 com.facebook.appmanager
That should uninstall the named package for the current user.
(You don't need root to uninstall system apps for the current user.)

Note this app will provide, by default, a list of all apps
you've installed, in the reverse order that you installed them.
*App Inspector* by UBQSoft
Free, ad free, gsf free, rated 4.3, 100K+ installs
<https://play.google.com/store/apps/details?id=com.ubqsoft.sec01>

C:\> adb shell pm install-existing com.facebook.appmanager
That should re-install that package that you had just uninstalled.
(This works because it was only uninstalled for the current user.)

C:\> adb shell pm disable-user --user 0 com.facebook.appmanager
That should disable the named package.

C:\> adb shell pm list packages -d | findStr /i "facebook"
That should find the disabled apps & then grep for "facebook".

C:\> adb shell pm enable com.facebook.appmanager
That should enable the named package.

C:\> adb shell pm uninstall com.facebook.appmanager
If you omit the "-k --user 0" part, it uninstalls for all users.

C:\> adb bugreport
That should create a zip file of your current bug-report data.

C:\> adb shell am start -n com.google.android.gms/.ads.settings.AdsSettingsActivity
That should pop up an Android "Reset Advertising ID" settings page.

C:\> adb shell input tap 500 400
If run after the command above, that will tap the button to
asking to "Opt out of Ads Personalization" in that Activity
if that button is like mine, at the X=500 & Y=400 location.

On my phone, this is the "Reset advertising ID" button location:
adb shell input tap 500 200
On my phone, this is the "OK" button on that GUI above.
adb shell input tap 700 1000

C:\> adb shell am force-stop com.google.android.gms
If run after bringing up the advertising-id reset Activity,
it will close the activity without doing anything else.

C:\> adb shell input keyevent KEYCODE_HOME
That should press the "Home" button.
C:\> adb shell input keyevent KEYCODE_CAMERA
That should press the "Camera" button.
C:\> adb shell input keyevent KEYCODE_BACK
That should press the "Back" button.
C:\> adb shell input keyevent KEYCODE_HEADSETHOOK
That should press the "Headset" button.
A list of hardcoded buttons is located in Android documentation:
<https://developer.android.com/reference/android/view/KeyEvent#constants_1>

C:\> adb pull /system/etc/hosts .\hosts.txt
[That should copy the hosts file over even if you're unrooted.]

C:\> adb shell dumpsys battery set level 4
That will _simulate_ (aka "spoof") a 4% battery level,
which may instantly cause a cascade of actions on your phone
as "if" your battery level really were low.

C:\> adb shell dumpsys battery set ac 1
That will _simulate_ (aka "spoof") that you just connected
an AC power adapter to your phone, so, for example, the phone
should show an icon and speak that you connected to AC power
if you've set this app to do that for you.
*Charging Indicator* by Jason A. Maderski
Free, ad free, gsf free, rated 4.2, 50K+ installs
<https://play.google.com/store/apps/details?id=maderski.chargingindicator>

Note that with adding notifications, I use text-to-speech to
clarify what the notification is telling me, instead of sounds.

Two text-to-speech free apps I use for notifications are:
*Tell Me - Text To Speech* by Simply Complex Apps
Free, ad free, +inapp $, rated 4.1, 100K+ installs
<https://play.google.com/store/apps/details?id=com.simplycomplexapps.ASTellme>

*NTM* Convert Text To Audio File by MEPROWORLD
Free, ad free, not rated, 10K+ installs
<https://play.google.com/store/apps/details?id=com.meproworld.ntm>

In the case of the battery indicators, I set notifications such as:
"Your battery just reached 100% charging"
"Your USB cable just disconnected"
etc.

C:\> adb shell dumpsys battery reset
This will turn off the battery-level simulation (aka spoofing).

C:\> adb shell dumpsys battery set ac 0
That will _simulate_ (aka "spoof") that you just dis-connected
an AC power adapter from your phone.

C:\> adb shell dumpsys battery set usb 1
That will _simulate_ (aka "spoof") that you just connected
a USB cable to your phone.
.
C:\> adb shell dumpsys battery set usb 0
That will _simulate_ (aka "spoof") that you just dis-connected
a USB cable to your phone.

C:\> adb shell pm list packages
That should list all installed packages.
C:\> adb shell pm list packages -s (list system packages only)
C:\> adb shell pm list packages -3 (list 3rd-party package names)
C:\> adb shell pm list packages -u (list uninstalled packages)
C:\> adb shell dumpsys package packages (list package information)
C:\> adb shell pm dump com.facebook.appmanager (info on one package)
C:\> adb shell pm path com.facebook.appmanager (package apk filespec)

C:\> adb shell pm list packages google | find /c /v ""
That should tell you the number of packages you have on Android
which have "google" in the package name.

C:\> adb shell am start -n com.android.settings/.Settings\$PowerUsageSummaryActivity
That should bring up a moving graph of your current battery usage.

C:\> adb shell am start -n com.google.android.gms/.location.settings.LocationAccuracyActivity
That should tell you if you have Google location spyware running.

C:\> adb shell am start -n com.google.android.gms/co.g.Space
That should allow you to clear your Google Play services storage.

C:\> adb shell am start -n com.google.android.gms/.update.SystemUpdateActivity
That should allow you to check for Android updates.

C:\> adb shell am start -n com.google.android.gms/.nearby.exposurenotification.settings.SettingsActivity
That will let you know your Covid exposure notification status.

C:\> adb shell am start -n com.google.android.gms/.app.settings.GoogleSettingsLink
That should bring up most of the Google privacy settings on Android.

C:\> adb shell am start -n com.android.settings/.Settings\$NotificationAppListActivity
That should bring up _all_ your extant notifications.

C:\> adb shell am start -n com.android.settings/.Settings\$AppMemoryUsageActivity
That should show you how much memory each app is using.

C:\> adb shell am start -n com.android.settings/.network.telephony.MobileNetworkActivity
That should tell you how much mobile data you've used up.

C:\> adb shell am start -n com.android.settings/.applications.ManageApplications
That should bring up the form to set your default Android apps.

C:\> adb shell am start -n com.google.android.gms/.gcm.GcmDiagnostics
That should scare the crap out of you when you see what it says!
mtalk.google.com is obtaining your private location information?

C:\> adb backup -all
Supposedly this will back up your entire device & app data to an
encrypted "backup.adb" file in your current Windows directory.

C:\> adb restore "C:\path-to\backup.adb"
Supposedly this will restore your backed up device & app data.
--
Posted out of the goodness of my heart to disseminate useful information
which, in this case, is to test which file managers can read root files.

Lars Anders

unread,
Nov 20, 2022, 9:42:38 PM11/20/22
to
On 21 Nov 2022, Andy Burnelli <sp...@nospam.com> wrote :

> If it doesn't do anything that the other file managers do, then I would
> ask why you let Google spyware onto your phone without a good reason.

https://www.hybrid-analysis.com/sample/67ecb5dd42039cca5d7ceeeb5273d2f3c92700c910d58eb7b35e5bc46d049e1f?environmentId=200
Google Services Framework_com.google.android.gsf.apk

Has the ability to get the wifi MAC address (may be used to fingerprint
device)
Has the ability to identify network operator related data
Has the ability to read the device ID (e.g. IMEI or ESN)

IP, Domain, Hash...
suspicious
Threat Score: 66/100AV Detection: Marked as clean
Google Services Framework_com.google.android.gsf.apk
This report is generated from a file or URL submitted to this webservice on
November 21st 2022 02:28:40 (UTC)
Report generated by Falcon Sandbox v7.00 © Hybrid Analysis

Incident Response
Risk Assessment
Fingerprint
Has the ability to get the wifi MAC address (may be used to fingerprint
device)
Has the ability to identify network operator related data
Has the ability to read the device ID (e.g. IMEI or ESN)
Indicators
Not all malicious and suspicious indicators are displayed. Get your own
cloud service or the full version to view all details.

Malicious Indicators2
General
Has the ability to read the device ID (e.g. IMEI or ESN)
details
Found invoke in "com.google.android.gsf.checkin.CheckinService.smali" to
"android.telephony.TelephonyManager.getSimSerialNumber"
Found invoke in "com.google.android.gsf.checkin.CheckinService.smali" to
"android.telephony.TelephonyManager.getSubscriberId"
Found invoke in
"com.google.android.gsf.checkin.CheckinRequestBuilder.smali" to
"android.telephony.TelephonyManager.getDeviceId"
source
Static Parser
relevance
3/10
Installation/Persistance
Has the ability to execute code after reboot
details
Permission request for "android.permission.RECEIVE_BOOT_COMPLETED"
source
Static Parser
relevance
10/10
Suspicious Indicators6
General
Uses java reflection classes
Network Related
Has the ability to open an internet connection
details
Found invoke in "com.google.android.gsf.update.DownloadAttempt.smali" to
"java.net.URL.openConnection"
Found invoke in "com.google.android.pano.widget.BitmapWorkerTask.smali" to
"java.net.URL.openConnection"
source
Static Parser
relevance
3/10
Hiding 4 Suspicious Indicators
All indicators are available only in the private webservice or standalone
version
Informative7
External Systems
Sample was identified as clean by Antivirus engines
General
Contains SQL queries
Requires permissions only available to signed APKs
details
Found permission request for "android.permission.UPDATE_DEVICE_STATS"
source
Static Parser
relevance
7/10
Requires permissions only available to signed APKs part of the system
details
Found permission request for "android.permission.ACCESS_CACHE_FILESYSTEM"
Found permission request for "android.permission.BACKUP"
Found permission request for "android.permission.MASTER_CLEAR"
Found permission request for "android.permission.REBOOT"
Found permission request for "android.permission.SET_TIME"
Found permission request for "android.permission.STATUS_BAR"
Found permission request for "android.permission.WRITE_GSERVICES"
Found permission request for "android.permission.WRITE_SECURE_SETTINGS"
source
Static Parser
relevance
7/10
Tests the internet connectivity
details
Found invoke in
"com.google.android.gsf.update.SystemUpdateService$UpdateTask.smali" to
"android.net.NetworkInfo.isConnected"
Found invoke in
"com.google.android.gsf.update.SystemUpdateService$UpdateTask.smali" to
"android.net.ConnectivityManager.getActiveNetworkInfo"
Found invoke in "com.google.android.gsf.update.StateWatcher.smali" to
"android.net.ConnectivityManager.getActiveNetworkInfo"
Found invoke in "com.google.android.gsf.checkin.CheckinService.smali" to
"android.net.ConnectivityManager.getActiveNetworkInfo"
Found invoke in "com.google.android.gsf.checkin.CheckinService.smali" to
"android.net.NetworkInfo.isConnected"
Found invoke in
"com.google.android.gsf.checkin.CheckinRequestBuilder.smali" to
"android.net.ConnectivityManager.getNetworkInfo"
Found invoke in
"com.google.android.gsf.checkin.CheckinRequestBuilder.smali" to
"android.net.wifi.WifiManager.getConnectionInfo"

Lars Anders

unread,
Nov 20, 2022, 9:45:02 PM11/20/22
to
On 21 Nov 2022, Andy Burnelli <sp...@nospam.com> wrote :

> <https://i.postimg.cc/fT7MSr90/root01.jpg> Even with All Files Access=On
> <https://i.postimg.cc/05wkPQ5n/root02.jpg> Half of file managers read root
> <https://i.postimg.cc/R0hm8Cbc/root03.jpg> & half of file managers do not

https://github.com/microg/GoogleServicesFramework/blob/master/src/com/google/android/gsf/gservices/GservicesProvider.java

package com.google.android.gsf.gservices;

import android.content.*;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.util.Log;

import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

public class GservicesProvider extends ContentProvider {

private static final BigInteger GOOGLE_SERIAL = new BigInteger("1228183678");
private static final char[] HEX_CHARS =
new char[]{'0', '1', '2', '3', '4', '3', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static final int KEY_COLUMN = 0;
private static final String TAG = "GoogleServicesProvider";
public static final Uri UPDATE_MAIN_DIFF_URI = Uri.parse("content://com.google.android.gsf.gservices/main_diff");
public static final Uri UPDATE_MAIN_URI = Uri.parse("content://com.google.android.gsf.gservices/main");
public static final Uri UPDATE_OVERRIDE_URI = Uri.parse("content://com.google.android.gsf.gservices/override");
private static final int VALUE_COLUMN = 1;

private DatabaseHelper dbHelper;
private boolean pushToSecure = false;
private boolean pushToSystem = false;
private TreeMap<String, String> values;

private final Object valuesLock = new Object();
private MessageDigest md;

private boolean checkCallingPermission(final String permission) {
return getContext().checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
}

private boolean checkPermissionOrSignature(final String permission, final BigInteger... serials) {
if (checkCallingPermission(permission)) {
return true;
}
for (BigInteger serial : serials) {
if (checkSignature(serial)) {
return true;
}
}
return false;
}

private boolean checkReadPermission() {
return checkPermissionOrSignature("com.google.android.providers.gsf.permission.READ_GSERVICES",
getSignatureSerials("com.google.android.gsf", GOOGLE_SERIAL));
}

private BigInteger[] getSignatureSerials(String packageName, BigInteger additionalSerial) {
ArrayList<BigInteger> serials = new ArrayList<BigInteger>();
try {
final PackageManager pm = getContext().getPackageManager();
final Signature[] sigs = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures;
final CertificateFactory factory = CertificateFactory.getInstance("X509");
for (final Signature sig : sigs) {
try {
final X509Certificate cert =
(X509Certificate) factory.generateCertificate(new ByteArrayInputStream(sig.toByteArray()));
if (cert.getSerialNumber() != null) {
serials.add(cert.getSerialNumber());
}
} catch (Exception e) {
// Try next
}
}
} catch (Exception e) {
// Ignore
}
if (additionalSerial == null) {
return serials.toArray(new BigInteger[serials.size()]);
} else {
BigInteger[] result = serials.toArray(new BigInteger[serials.size() + 1]);
result[serials.size()] = additionalSerial;
return result;
}
}

private boolean checkSignature(final BigInteger serial) {
try {
final PackageManager pm = getContext().getPackageManager();
final String packageName = pm.getNameForUid(Binder.getCallingUid());
final BigInteger[] serials = getSignatureSerials(packageName, null);
for (BigInteger s : serials) {
if (s.equals(serial)) {
return true;
}
}
} catch (final Throwable t) {
}
return false;
}

private boolean checkWritePermission() {
return checkPermissionOrSignature("com.google.android.providers.gsf.permission.WRITE_GSERVICES",
getSignatureSerials("com.google.android.gsf", GOOGLE_SERIAL));
}

private boolean computeLocalDigestAndUpdateValues() {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
final TreeMap<String, String> map = new TreeMap<String, String>();
md.reset();
String oldDigest = null;
db.beginTransaction();
Cursor cursor = db.rawQuery("SELECT name, value FROM main ORDER BY name", null);
try {
while (cursor.moveToNext()) {
final String key = cursor.getString(KEY_COLUMN);
final String value = cursor.getString(VALUE_COLUMN);
if (!key.equals("digest")) {
md.update(key.getBytes());
md.update((byte) 0);
md.update(value.getBytes());
md.update((byte) 0);
} else {
oldDigest = value;
}
map.put(key, value);
}
} finally {
cursor.close();
}
final StringBuilder sb = new StringBuilder("1-");
final byte[] hash = md.digest();
for (final byte element : hash) {
sb.append(HEX_CHARS[0xf & element >> 4]);
sb.append(HEX_CHARS[element & 0xf]);
}
final String digest = sb.toString();
map.put("digest", digest);

if (!digest.equals(oldDigest)) {
ContentValues contentValues = new ContentValues();
contentValues.put("name", "digest");
contentValues.put("value", digest);
db.insertWithOnConflict("main", null, contentValues, SQLiteDatabase.CONFLICT_REPLACE);
}
cursor = db.rawQuery("SELECT name, value FROM overrides", null);
try {
while (cursor.moveToNext()) {
map.put(cursor.getString(KEY_COLUMN), cursor.getString(VALUE_COLUMN));
}
} finally {
cursor.close();
}
synchronized (valuesLock) {
values = map;
}
db.setTransactionSuccessful();
db.endTransaction();
return !digest.equals(oldDigest);
}

@Override
public int delete(final Uri arg0, final String arg1, final String[] arg2) {
throw new UnsupportedOperationException();
}

private String getPrefixLimit(final String string) {
for (int i = string.length() - 1; i > 0; i--) {
final char c = string.charAt(i);
if (c < '\uFFFF') {
return string.substring(0, i) + (char) (c + 1);
}
}
return null;
}

@Override
public String getType(final Uri uri) {
return null;
}

@Override
public Uri insert(final Uri uri, final ContentValues values) {
throw new UnsupportedOperationException();
}

@Override
public boolean onCreate() {
try {
md = MessageDigest.getInstance("SHA-1");
} catch (Exception e) {
Log.w(TAG, "Can't hash digest, this will cause problems!", e);
}
dbHelper = new DatabaseHelper(getContext());
final int pid = Process.myPid();
final int uid = Process.myUid();
if (getContext().checkPermission("android.permission.WRITE_SETTINGS", pid, uid) == PackageManager.PERMISSION_GRANTED) {
pushToSystem = true;
}
if (getContext().checkPermission("android.permission.WRITE_SECURE_SETTINGS", pid, uid) == PackageManager.PERMISSION_GRANTED) {
pushToSecure = true;
}
computeLocalDigestAndUpdateValues();
return true;
}

@Override
public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs,
final String sortOrder) {
if (!checkReadPermission()) {
Log.d(TAG, "no permission to read during query(" + uri + ", " + projection + ", " + selection + ", " +
selectionArgs + ", " + sortOrder + ")");
throw new UnsupportedOperationException();
}
final MatrixCursor cursor = new MatrixCursor(new String[]{"key", "value"});
if (selectionArgs != null) {
final String lastSegment = uri.getLastPathSegment();
if (lastSegment == null) {
querySimple(cursor, selectionArgs);
} else if (lastSegment.equals("prefix")) {
queryPrefix(cursor, selectionArgs);
}
}
return cursor;
}

private void queryPrefix(final MatrixCursor cursor, final String... selectionArgs) {
for (final String arg : selectionArgs) {
final String limit = getPrefixLimit(arg);
SortedMap<String, String> sortedmap;
if (limit == null) {
sortedmap = values.tailMap(arg);
} else {
sortedmap = values.subMap(arg, limit);
}
for (final Entry<String, String> entry : sortedmap.entrySet()) {
cursor.addRow(new String[]{entry.getKey(), entry.getValue()});
}
}
}

private void querySimple(final MatrixCursor cursor, final String[] keys) {
synchronized (valuesLock) {
for (final String key : keys) {
cursor.addRow(new String[]{key, values.get(key)});
}
}
}

private void syncAllSettings() {
if (pushToSystem) {
syncSettings(android.provider.Settings.System.CONTENT_URI, "system:", "saved_system");
}
if (pushToSecure) {
syncSettings(android.provider.Settings.Secure.CONTENT_URI, "secure:", "saved_secure");
}
}

private void syncSettings(final Uri uri, final String prefix, final String table) {
final MatrixCursor cursor = new MatrixCursor(new String[]{"key", "value"});
queryPrefix(cursor, prefix);
// TODO Auto-generated method stub
Log.w(TAG, "Not yet implemented: GservicesProvider.syncSettings");
}

@Override
public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
if (!checkWritePermission()) {
Log.d(TAG, "no permission to write during update(" + uri + ", " + values + ", " + selection + ", " +
selectionArgs + ")");
throw new UnsupportedOperationException();
}
final String lastSegment = uri.getLastPathSegment();
if (lastSegment.equals("main") && updateMain(values) ||
lastSegment.equals("main_diff") && updateMainDiff(values) ||
lastSegment.equals("override") && updateOverride(values)) {
getContext().sendBroadcast(new Intent("com.google.gservices.intent.action.GSERVICES_CHANGED"));
return 1;
}
return 0;
}

private boolean updateMain(final ContentValues values) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.insertWithOnConflict("main", null, values, SQLiteDatabase.CONFLICT_REPLACE);
db.close();
if (computeLocalDigestAndUpdateValues()) {
Log.d(TAG, "changed " + values.get("name") + " to " + values.get("value") + " and digest is now " + this.values.get("digest"));
return true;
}
return false;
}

private boolean updateMainDiff(final ContentValues values) {
Log.w(TAG, "Not yet implemented: GservicesProvider.updateMainDiff: " + values);
return false;
}

private boolean updateOverride(final ContentValues values) {
Log.w(TAG, "Not yet implemented: GservicesProvider.updateOverride: " + values);
return false;
}

public static class OverrideReceiver extends BroadcastReceiver {

@Override
public void onReceive(final Context context, final Intent intent) {
final Bundle bundle = intent.getExtras();
if (bundle != null) {
final ContentValues values = new ContentValues();
for (final String key : bundle.keySet()) {
values.put(key, bundle.getString(key));
}
context.getContentResolver().update(UPDATE_OVERRIDE_URI, values, null, null);
}
}

}
}
0 new messages