3889 Commits

Author SHA1 Message Date
Hans-Christoph Steiner
748352e5a1 do not update InstalledAppProvider if already current
This adds a check of whether the database has the current APK in it, based
on PackageInfo's lastUpdateTime field.  This avoids recalculating the hash
of the whole APK, which is quite time and resource intensive.
2016-06-02 10:22:07 +02:00
Hans-Christoph Steiner
90467bf8bf InstalledAppProvider: store APK hash and last update time
The APK hash is useful for comparing whether something is exactly the same
file as something else.  For example, to compare whether the installed APK
matches something that f-droid.org hosts.  The "last update time" is a fast
way to check whether the information is current.
db-version/56
2016-06-02 10:22:07 +02:00
Hans-Christoph Steiner
906a26414a rate limit InstallApp install/delete notifications to 1000ms
InstallAppProviderService now processes install and delete events one at a
time, where InstalledAppCacheUpdater made a batch of changes which it ran
all at once.  This means that InstallAppProviderService will send out a
flood of notifications when first initializing, since it will index every
single installed app and send a notification for each one.  This makes the
GUI lock up. This commit puts a rate limit on those notifications if they
start coming fast.  They are limited to one per second.
2016-06-02 08:36:31 +02:00
Hans-Christoph Steiner
d734e584f6 InstalledAppProviderService to replace InstalledAppCacheUpdater
InstalledAppCacheUpdater was a custom Service-like thing with some
threading issues.  InstalledAppProviderService is an IntentService that
relies on the built-in queue and threading of the IntentService to make
sure that things are processed nicely in the background and one at a time.

This changes the announcing so that each app added/changed/deleted triggers
a new annoucement.  This keeps the UI more updated, and makes the Installed
tab show something as soon as possible, rather than waiting for the all of
the install apps to be processed.  This becomes more important as more
stuff is added to InstalledAppProvider, like the hash of the APK.

This also strips down and simplifies the related BroadcastReceivers.
BroadcastReceivers work on the UI thread, so they should do as little work
as possible. PackageManagerReceiver just rebadges the incoming Intent and
sends it off to InstalledAppProviderService for processing.
2016-06-02 08:36:30 +02:00
Hans-Christoph Steiner
677db72bb3 Utils.getPackageUri() for creating Uris from packageNames
Since this is done a lot, might as well have a reusable method.
2016-06-02 08:36:30 +02:00
Hans-Christoph Steiner
ae3ea85355 SwapService should be running as long as anything swap is active
The SwapService is the central container for all things swap.  If anything
at all related to swap is active, then SwapService needs to be running.
That also means that stopping SwapService should stop all things related to
swapping, including any screens or notifications.

fixes #258 https://gitlab.com/fdroid/fdroidclient/issues/258
2016-06-02 08:36:30 +02:00
Hans-Christoph Steiner
335be87cf8 new CacheSwapAppsService for caching parsed apps to be swapped
Since it takes a chunk of time to generate and write the app index.jar when
swapping apps, this service starts running in the background immediately
when SwapService starts.  It first indexes the installed apps that were not
cached, then caches apps based PACKAGE_ADDED broadcasts.  It does not index
system apps, since there are many and they are rarely swapped.
2016-06-02 08:36:30 +02:00
Hans-Christoph Steiner
944d355e29 swap: skip writing index.xml, output straight to index.jar
This makes the index generation noticeably faster.  This also converts
IndexXmlBuilder to a singleton, since that's how it is used.
2016-06-02 08:36:30 +02:00
Hans-Christoph Steiner
3ec206b152 simplify local repo XML writing and remove dead code
This has a couple of things stuck in it that aren't really used at all,
like maxage.
2016-06-02 08:36:30 +02:00
Dominik
de238f3f5f Merge branch 'InstallManagerService-completion' into 'master'
InstallManagerService completion

This is a collection of fixes to finalize `InstallManagerService` now that !300 is merged.

See merge request !318
2016-06-01 22:23:50 +00:00
Hans-Christoph Steiner
43e902407f add some javadoc notes about the new installer stuff 2016-06-01 22:29:37 +02:00
Hans-Christoph Steiner
e95dec30b5 remove APK from active list if install process is interrupted
If the install process is interrupted, then InstallManagerService is no
longer managing it.  It will make the announcements and set the
notification, then forget about that APK.
2016-06-01 22:29:37 +02:00
Hans-Christoph Steiner
07cadd862a Installer IntentFilters must also match on host and port
Without this rule, two https:// URLs with the same path and APK name would
both match.  With multiple repo and swap support, this could easily happen.
2016-06-01 22:29:37 +02:00
Hans-Christoph Steiner
738a92f5d2 reduce visibility of installer extra constants
This should encourage devs to stick with the nice static methods that are
the "public" API.
2016-06-01 22:29:37 +02:00
Hans-Christoph Steiner
f949c5807f make swap install via InstallManagerService
Somehow, it ended up that there was a partial reimplementation of the
install in SwapWorkflowActivity.
2016-06-01 22:29:36 +02:00
Hans-Christoph Steiner
9d2fe4000d use download URL as unique ID through the whole install process
InstallManagerService and DownloaderService both use the download URL as
the unique ID to represent a given APK install through the whole lifecycle
of the install and download process.  This converts the installer stuff to
use the same semantics.  A Uri instance is mostly used there because its
the most useful format, but ultimately, the String, Uri, and int all derive
from the exact same URL.  This then removes the local APK URI from use in
the installer broadcasts.

While I normally think reusing terms from Android is the best thing to do,
"originating URI" drives me nuts because it is almost nonsense English.
"Originating" is a verb in the continuous form, meaning that it is an
action that is ongoing.  A URI is a static thing, and in this case, a URI
that points to a file that is completely downloaded.  I left the term in
place for DefaultInstaller because it wraps PackageManager, which is where
that term originates.

This handles "Use strings instead of Uris in InstallManagerService for
urlString" as listed in #680
2016-06-01 22:29:36 +02:00
Hans-Christoph Steiner
7385d320b4 fix crash when UpdateService receives null Intent
IntentServices can get a null Intent if they are restarted after being
killed.  So this should be properly handled.

"[The intent] may be null if the service is being restarted after its
process has gone away, and it had previously returned anything except
START_STICKY_COMPATIBILITY."
https://developer.android.com/reference/android/app/IntentService.html#onStartCommand(android.content.Intent,%20int,%20int)

ANDROID_VERSION=5.1.1
APP_VERSION_NAME=0.99.2
BRAND=samsung
PHONE_MODEL=SM-G901F
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.getStringExtra(java.lang.String)' on a null object reference
	at org.fdroid.fdroid.UpdateService.onHandleIntent(UpdateService.java:342)
	at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
	at android.os.Handler.dispatchMessage(Handler.java:102)
	at android.os.Looper.loop(Looper.java:135)
	at android.os.HandlerThread.run(HandlerThread.java:61)
2016-06-01 21:00:10 +02:00
Hans-Christoph Steiner
6166d9afc9 fix random crash in WifiStateChangeService
Some of these devices do shitty things.

htc_europe HTC EVO 3D X515m

java.lang.RuntimeException: An error occured while executing doInBackground()
 at android.os.AsyncTask$3.done(AsyncTask.java:278)
 at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
 at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
 at java.util.concurrent.FutureTask.run(FutureTask.java:137)
 at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
 at java.lang.Thread.run(Thread.java:864)
Caused by: java.lang.NullPointerException
 at java.net.NetworkInterface.getNetworkInterfacesList(NetworkInterface.java:286)
 at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:262)
 at org.fdroid.fdroid.net.WifiStateChangeService.setIpInfoFromNetworkInterface(WifiStateChangeService.java:202)
 at org.fdroid.fdroid.net.WifiStateChangeService.access$300(WifiStateChangeService.java:37)
 at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:99)
 at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:71)
 at android.os.AsyncTask$2.call(AsyncTask.java:264)
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
 ... 5 more
java.lang.NullPointerException
 at java.net.NetworkInterface.getNetworkInterfacesList(NetworkInterface.java:286)
 at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:262)
 at org.fdroid.fdroid.net.WifiStateChangeService.setIpInfoFromNetworkInterface(WifiStateChangeService.java:202)
 at org.fdroid.fdroid.net.WifiStateChangeService.access$300(WifiStateChangeService.java:37)
 at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:99)
 at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:71)
 at android.os.AsyncTask$2.call(AsyncTask.java:264)
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
 at java.util.concurrent.FutureTask.run(FutureTask.java:137)
 at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
 at java.lang.Thread.run(Thread.java:864)
2016-06-01 21:00:10 +02:00
Hans-Christoph Steiner
984a507ffa fix random crash in WifiStateChangeService
java.lang.NullPointerException: Attempt to invoke virtual method
'android.os.Parcelable android.content.Intent.getParcelableExtra(java.lang.String)' on a null object reference
  at org.fdroid.fdroid.net.WifiStateChangeService.onHandleIntent(WifiStateChangeService.java:56)
  at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:135)
  at android.os.HandlerThread.run(HandlerThread.java:61)

fixes #559
2016-06-01 21:00:10 +02:00
Hans-Christoph Steiner
9c1b917604 Merge branch 'installerservice-wip' into 'master'
InstallerService

This merge request mainly introduces the ``InstallerService``. Many files have been touched and reworked in this merge request, due to the following changes:
* After download of an apk in ``InstallManagerService``, the ``InstallerService``is started an kicks off the installation process. For unattended installers this directly runs through without any user interaction, for the default installer a new PendingIntent containing ``DefaultActivityInstaller`` is returned that is either stuffed into the notification or directly started from ``AppDetails``
* Using local broadcasts, ``InstallManagerService`` and ``AppDetails`` are informed of state changes in the installation process
* ``DefaultActivityInstaller`` is a wrapper around the default installation APIs of Android
* If the unattended ``PrivilegedInstaller`` is available, a permission screen is shown before download
* Actual error codes and messages are displayed in notification or dialog on fail, especially interesting when using the ``PrivilegedInstaller``
* The process for installing the Privileged Extension has been moved into an own installer for logic seperation, called ``ExtensionInstaller``

Some design considerations:
* I try to use Uris where ever possible. At some points this clashes with the usage of ``urlString`` in ``InstallManagerService``. This could be fixed in a later merge request

Some other TODOs are left, but I would like to do them after this merge request has been merged if it's okay, as this one is already too huge:
* Check if apk permissions are the same as announced in the permission screen for ``PrivilegedInstaller``
* In ``Installer.newPermissionCount()``, I need the target SDK before download to check if it's targetting Android M, which does not require the permission screen
* Introduce FileProvider for Android N
* Redesign layout of ``InstallConfirmActivity``
* Remove "cancel" icon for installing progress in AppDetails

See merge request !300
2016-06-01 15:06:38 +00:00
Dominik Schürmann
b149cd64fd Removes remaining scopes from switch statements 2016-06-01 14:12:59 +02:00
Dominik Schürmann
619c4f284b Fix crash for apks with no permissions 2016-06-01 02:14:54 +02:00
Dominik Schürmann
1aa87ddf76 PrivilegedInstaller: Fix check for granted permissions
The onConnected callback of ServiceConnection is always
executed on the main looper of the context that is used
to create the service binding. Thus the old code resulted
in a deadlock and then in a timeout of the Thread.wait()
method.

The check for permissions is now called inside install and
uninstall callbacks, where it works asynchronously.
2016-06-01 02:14:51 +02:00
Dominik Schürmann
0b92806327 New error dialog on failed installs 2016-05-31 22:44:58 +02:00
Dominik Schürmann
5f1b7488f0 More Log.e for isExtensionInstalledCorrectly 2016-05-31 17:52:45 +02:00
Dominik Schürmann
886c67e452 Fix NPE for uninstall of extension 2016-05-31 17:28:55 +02:00
Dominik Schürmann
c5ae43d66c Remove UI code from PrivilegedInstaller 2016-05-31 17:15:07 +02:00
Dominik Schürmann
9e0787f23d Add javadoc to installer classes 2016-05-31 17:15:07 +02:00
Dominik Schürmann
b994b1c895 Fix selection of ExtensionInstaller 2016-05-31 17:15:07 +02:00
Dominik Schürmann
13f2e30a40 Make InstallerService an IntentService
Because only one apk should be installed at a time
and no cancelation is required it is sufficient to
use an IntentService
2016-05-31 17:15:07 +02:00
Dominik Schürmann
d6803e1bf4 Remove scopes from switch statements
also change two-case switch statements to if-else
2016-05-31 17:15:07 +02:00
Dominik Schürmann
f860257826 Fix pmd errors and code style 2016-05-31 17:15:07 +02:00
Dominik Schürmann
d3a7107a0f Fix checkstyle errors 2016-05-31 17:15:07 +02:00
Dominik Schürmann
2776b86050 Redesign PrivilegedInstaller
* use new local broadcasts
* show permission screen before download
* display permission screen as dialog
2016-05-31 17:15:07 +02:00
Dominik Schürmann
592cd0424a Better error handling for priv installer 2016-05-31 17:14:31 +02:00
Dominik Schürmann
4e8e148029 Display install errors as notify/dialog 2016-05-31 17:14:31 +02:00
Dominik Schürmann
de1d310499 Move installation of extension into own Installer 2016-05-31 17:14:31 +02:00
Dominik Schürmann
c5f9070370 Better error handling in privileged installer 2016-05-31 17:14:31 +02:00
Dominik Schürmann
bb273cd2f5 Use Uris more often instead of File 2016-05-31 17:14:31 +02:00
Dominik Schürmann
a2356b05d6 Refactor installer package 2016-05-31 17:13:53 +02:00
Dominik Schürmann
6d2f2d20a8 InstallerService 2016-05-31 17:13:26 +02:00
Hans-Christoph Steiner
4ef0642134 Merge branch 'ci-bumps' into 'master'
PMD and Checkstyle version bumps



See merge request !316
2016-05-31 14:39:04 +00:00
Daniel Martí
08e067c6ba pmd: bump to 5.4.2
This is a bugfix release where they mostly fixed false positives. No
changes required.
2016-05-30 22:08:19 +01:00
Daniel Martí
d4bb97db72 checkstyle: bump to 6.19
Seems like they finally fixed the hanging throws indent issue.
2016-05-30 22:04:33 +01:00
Daniel Martí
5e2da57565 Merge branch 'bump-minsdk' into 'master'
Bump minSdkVersion to 10, remove all compat code

Summary of changes:

* Remove compat apply()
* Remove compat setReadable()
* Remove pre-10 compat code in swap
* Remove pre-10 compat code in PRNGFixes

Fixes #663.

See merge request !296
2016-05-30 18:40:38 +00:00
Daniel Martí
cd1c213fb2 Bump minSdkVersion to 10, remove all compat code
Summary of changes:

* Remove compat apply()
* Remove compat setReadable()
* Remove pre-10 compat code in swap
* Remove pre-10 compat code in PRNGFixes

Fixes #663.
2016-05-30 19:25:06 +01:00
Daniel Martí
1bfd3425c9 Merge branch 'prep-for-InstalledAppProviderService' into 'master'
Prep for InstalledAppProviderService

This is basically a collection of little fixes in preparations for !299 .

See merge request !313
2016-05-27 20:31:00 +00:00
Hans-Christoph Steiner
a03629d29d SanitizedFileTest requires systems with "/" for a path separator
closes #622 https://gitlab.com/fdroid/fdroidclient/issues/622
2016-05-27 22:00:28 +02:00
Hans-Christoph Steiner
1914f5f3e1 remove unused app.uninstallable
app.uninstallable is only used in AppDetails.  It is only set when
generating App instances from installed APKs for the swap stuff. Since it
is initialized to false and used as !app.uninstallable, it is always true
when used.  So it was doing nothing.

This needs to be thought out more so this is not entirely complete for
#628. AppDetails needs to know whether its a system app to provide proper
feedback and swap needs to know whether its a system app with an update
installed, otherwise it should ignore it.
2016-05-27 22:00:28 +02:00
Hans-Christoph Steiner
f7688d7f9a convert App comments to javadoc so they can be read in popups, etc.
Decent Java editors have all sorts of nice ways to show javadoc comments,
whether they are for public or private APIs.  So comments should be in that
format whenever possible.
2016-05-27 22:00:28 +02:00