The fact that sqlite chose to do a "FULL TABLE SCAN" right off the bat when showing a list
of apps results in it having to do extra work at the end of the query to sort. If the scan
can be utilise an index, then the sorting is already done and a b-tree need not be constructed.
Thus, this introduces indexes for both the `name` column (used to sort most lists of apps)
and the `added` column (used to figure out the `Whats New` apps).
This is required because SQLite "rowids" are 64 bit integers:
> all rows within SQLite tables have a 64-bit signed integer
> key that uniquely identifies the row within its table."
https://sqlite.org/lang_createtable.html#rowid
This is important for the ability to refactor the database for better performance in the future.
See #511 for details.
For those interested in the details, here is a query plan of selecting the "All" category of apps before
this commit:
* `SCAN TABLE fdroid_app USING INDEX app_id`
* `SEARCH TABLE fdroid_apk USING INDEX apk_id (id=?)`
* `SEARCH TABLE fdroid_repo USING INTEGER PRIMARY KEY (rowid=?)`
* `SEARCH TABLE fdroid_installedApp AS installed USING INDEX sqlite_autoindex_fdroid_installedApp_1 (appId=?)`
* `SEARCH TABLE fdroid_apk AS suggestedApk USING INDEX sqlite_autoindex_fdroid_apk_1 (id=? AND vercode=?)`
* `USE TEMP B-TREE FOR ORDER BY`
And here is a query plan of afterwards:
* `SCAN TABLE fdroid_app`
* `SEARCH TABLE fdroid_apk USING INDEX apk_appId (appId=?)`
* `SEARCH TABLE fdroid_repo USING INTEGER PRIMARY KEY (rowid=?)`
* `SEARCH TABLE fdroid_installedApp AS installed USING INDEX sqlite_autoindex_fdroid_installedApp_1 (appId=?)`
* `SEARCH TABLE fdroid_apk AS suggestedApk USING INDEX apk_appId (appId=?)`
* `USE TEMP B-TREE FOR ORDER BY`
The things of note are:
* `SCAN TABLE` doesn't use an index, which means that it is really using the rowid index. Shouldn't behave much differently.
* The second item now uses an integer primary key index rather than a package name index. Should increase search speed marginally which was the goal of this commit. As more apks exist, the speed improvement will also increase.
This class is used by `AppDetails` without an API verison check around its access.
Thus, we call methods on this that are unsupported when on gingerbread.
By removing `TargetApi` from the class, it unearthed a couple of locations
where methods were being invoked without first guarding against the build version
correctly. These two locations have been fixed and a `TargetApi` attached to the
more narrowly defined method which requires it.
SQLite has a very nice "EXPLAIN QUERY PLAN" command (https://sqlite.org/eqp.html).
It is not really meant to be used in production code, as per the docs, but it is
super helpful at diagnosing missing indexes or other performance problems with
databases. I find it much better than, for example, the MySQL alternative.
This commit routes queries from the `ApkProvider` and `AppProvider` through a
`LoggingQuery` which (in debug builds) times queries, and if they take longer
than a certain threshold, outputs them to logcat. In addition, it will then
ask sqlite to explain its query plan for that same query, and output that to
logcat too.
Right now, table names are in `DBHelper.TABLE_*` constants, and each tables fields are
in `*Provider.DataColumns.*` constants. This brings them all into a predictable location.
In addition, it makes it easier to statically import `Schema` so that instead of, e.g.,
* `AppProvider.DataColumns.PACKAGE_NAME`
We can choose one of the following, based on our current context:
* `Schema.AppTable.Cols.PACKAGE_NAME`
* `AppTable.Cols.PACKAGE_NAME`
* `Cols.PACKAGE_NAME`
In the worst case, it isa couple of chars shorter than now. In the best case, if we are
writing a class that primarily deals with Apps (e.g. App.java or AppProvider.java) then
we get a big win with just `Cols.PACKAGE_NAME`.
Having these things slightly shorter may seem like it is pointless, but the length of
each constant probably contributed to my lack of willingness to use constants instead
of string literals when constructing queries.
In the future, this should be moved towards something more akin to:
> http://openhms.sourceforge.net/sqlbuilder/
and I hope that extracting all the schema stuff into one interface may help that.
java.lang.NullPointerException
at org.fdroid.fdroid.Utils.clearOldFiles(Utils.java:347)
at org.fdroid.fdroid.CleanCacheService.onHandleIntent(CleanCacheService.java:51)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:194)
at android.os.HandlerThread.run(HandlerThread.java:60)
Also change the overrides from onCreate to init as suggested in the
changelog:
https://github.com/ACRA/acra/wiki/ChangeLog#acra-490-rc-1-2-may-2016
The behaviour should be very similar, although overriding the wrong
method (which we were doing) could cause all sorts of weird issues.
This is currently baffling me as to how it can happen. This isn't a pretty
fix but it is better that letting F-Droid crash. db9bdc31 was supposed to
make it so that only one thread at a time ever updated the static vars on
FDroidApp.
closes#690
UpdateService.onHandleIntent() starts with a time check for whether an
update is actually scheduled. Before, UpdateService put up a notification
when it started. This changes it so that the notification is put up after
the check, so it should only show the notification if UpdateService is
actually going to run, and no longer when it is just waking up to check the
time.
!307#662
Provide content Uris to downloaded apks via FileProvider
* moves apk verification back inside the Installer class
* uses support libs FileProvider for content Uris
* move apk file caching and storage methods into ApkFileProvider class
Some of the ugly version checks for Android N can be removed after Android N has been released. Unfortunately Google decided to keep SDK version at 23 for Android N dev preview and only change the CODENAME, thus ``Build.VERSION.SDK_INT <= Build.VERSION_CODES.M`` returns true on Android N preview :/ , see https://commonsware.com/blog/2016/03/17/backwards-compatibility-n-developer-preview.html
Tested on Android N dev preview 3 emulator, Android 6 stock and Android 5.1 rooted with priv extension.
See merge request !331
The two helper methods alleviate the need for copious null checks. They also provide
consistent behaviour when there are zero elements (i.e. they return null, rather than
an empty string or empty array, as was the case before).
This is a combination of:
* `String[].split(",")` and
* `TextUtils.join(",", values)`
It seems a bit wastefull to have our own implementation of these two things
which lightly wrap this code, and produce a datastructure which is non standard
and foreign to Java developers.
* moves apk verification back inside the Installer class
* uses support libs FileProvider for content Uris
* move apk file caching and storage methods into
ApkCache class
We missed an off-by-one in my previous DB change:
90467bf8bf2f8e4a46cb1db563154df4035bf746
This causes the installed app parsing to happen on each start when on any
build that is on db-version/56. Its not a big deal since the broken code
was not shipped at all, even in an alpha.
In order to avoid having null guards making the code ugly, use a "blank"
instance of Apk which will work for the various comparisons. This fixes
this crash:
fixes#688
java.lang.NullPointerException
at org.fdroid.fdroid.installer.InstallManagerService$4.onReceive(InstallManagerService.java:243)
at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:297)
at android.support.v4.content.LocalBroadcastManager.access$000(LocalBroadcastManager.java:46)
at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:116)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Improve order by/selection logic for database layer.
This was extracted from the postponed !311.
The order by stuff previously only allowed specifying a particular field. We should also be able to sort based on arbitrary expressions, and such expressions will require the ability to bind arguments using the "?" syntax. This change provides a Java abstraction for the order by, and improves the handling of selection arguments that need to bind to "?" so that both the selection (i.e. `WHERE` clause) and the `ORDER BY` clause can provide arguments as required.
See merge request !329
A previous commit accidentally pushed the code which queries the
`PackageManager` to a different method, but then still used the
`packageInfo` which was supposed to be populated by that code.
This change rectifies this, and in the process also clarifies/documents under
what circumstances the `PackageManager` needs to be queried, rather than
relying on the incoming intent.
Fixes#686.
The order by stuff previously only allowed specifying a particular field.
We should also be able to sort based on arbitrary expressions, and such
expressions will require the ability to bind arguments using the "?" syntax.
This changes provides a Java abstraction for the order by, and improves
the handling of selection arguments that need to bind to "?" so that both
the selection (i.e. WHERE clause) and the ORDER BY clause can provide
arguments as required.
It is not a particularly expensive operation in the scheme of things. When we
are going to the database, the bottlneck is in disk access for the actual query
of the database tables. The difference between retrieving two columns or
all the columns when the query is for a handful of apps is inconsequential.
Thus, it is better to be safe than sorry and just ask for all the things so
that our value objects are correctly populated.
Permissions UI in AppDetails
* Removes the "m" prefix and some unnecessary TODOs
* Re-uses the permission list from the privileged installer for the list in AppDetails:

See merge request !332
include targetSdkVersion in Apk
In order to work well with the Android 6.0+ permissions, the client needs to know whether an APK has been built against android-23 or higher.
@pserwylo @dschuermann how does this look?
See merge request !323