-
Notifications
You must be signed in to change notification settings - Fork 1.3k
FNX-14633 ⁃ For #162 - Add OSS build flavor. #13453
Conversation
No Taskcluster jobs started for this pull requestThe `allowPullRequests` configuration for this repository (in `.taskcluster.yml` on the
default branch) does not allow starting tasks for this pull request. |
8df86dd
to
a893b22
Compare
a893b22
to
19a6825
Compare
fa26bd8
to
6e1a949
Compare
This is to ensure both free and non-free implementations are updated when an interface is added to the base service, like in 77263aa.
6e1a949
to
3e021e4
Compare
import android.net.Uri | ||
import java.util.UUID | ||
|
||
class LeanplumMetricsServiceImpl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LeanplumMetricsService is used for two cases, both of which already have interfaces. Rather than making a dummy metrics service, let's configure those two locations.
First one is easy, the service is used in MetricController.create and discarded if the Telemetry flag is set to false. No change needed.
Second location is for the DeepLinkIntentProcessor. It wants a DeepLinkVerifier instance. You could pass in a dummy version that always returns false based on build flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First one is easy, the service is used in MetricController.create and discarded if the Telemetry flag is set to false. No change needed.
Since you can't include LeanplumMetricsService
in main sources because of the imports, you still need a dummy implementation somewhere at least to make the compiler happy when building the free variant. Or are you suggesting to defer this at runtime by using reflection? What am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I think I was getting confused with BuildConfig flags and build variants. I thought this could be accomplished with an if statement.
Are we allowed to use any form of telemetry in the F-Droid version? If not, we may want to replace the entire MetricController. We have a dummy DebugMetricController
already that could be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we allowed to use any form of telemetry in the F-Droid version?
I'm pretty sure that yes, telemetry is allowed as long as the frameworks being used are completely FLOSS (so Glean and Adjust should be OK, not firebase because of the dependency to gms). You can even display ads under the same conditions.
However, telemetry, especially when enabled by default like it is in Fenix, is considered an "anti-feature". This means there will be a warning prior downloading the app on the store. Such warning is already displayed for Fennec, so that's not too bad I guess.
|
||
class OssLicensesMenuImpl : OssLicensesMenu { | ||
override fun getIntent(context: Context?, title: String): Intent { | ||
// This menu shouldn't displayed on the free variant anyways. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? AFAIK open source libraries should be fine to leave in, and we'll need to credit them to use them in the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I don't know why I thought it wasn't required for OSS software 🤐 . So I replaced Google's library with AboutLibraries which is the most popular FLOSS alternative I could find and it just looks better.
Note that I had to pin android gradle because AboutLibraries has gradle:4.0.0
which isn't compatible with Fenix yet (#13262). For the records, I quickly checked what were the blockers to upgrading the android gradle plugin and I found that the glean-gradle-plugin is incompatible: getBuildConfigPackageName()
now returns a Property
so you have to call get()
on it. Also, I also had to update the RepoMatching like this:
- const val comAndroid = "com\\.android\\..*"
+ const val comAndroid = "com\\.android(\\..+)?"
I don't think those two changes are sufficient to update because there are more subtle issues with the components, but at least these could easily be addressed in other PRs.
Out of curiosity, I also looked how the licenses menu worked in Fennec, and it turns out Fennec just opens about:license
, which doesn't list Android dependencies. We could fallback to this, but I don't think it's a fair solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still a bit confused here. Why can't we use the Google library? As far as I can tell its open source and just figures out the play services libraries we use, rather than depending on them.
If we need to change the license implementation I think it would be nice to have it split into a separate PR so its easier to review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it is confusing. The gradle plugin that lists the dependencies is open-source and under Apache 2 license, but the library that is shipped with the APK is proprietary and, as far as I can tell, closed-source. Morever, the library has dependencies to gms (which you can easily see with dexdump) which is unsuitable for OSS anyways.
Agreed that it would make sense to split this into a separate PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks for breaking it down. Using the most popular FLOSS version instead makes sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app/build.gradle
Outdated
@@ -17,6 +17,8 @@ import org.mozilla.fenix.gradle.tasks.LintUnitTestRunner | |||
|
|||
import static org.gradle.api.tasks.testing.TestResult.ResultType | |||
|
|||
def useFreeImplementation = project.properties['org.mozilla.fenix.useFreeImplementation'].toBoolean() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be better off as another build variant, like debug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my original intention, but wasn't sure how to exclude dependencies for a specific build type. Sure you can add new dependencies like debugImplementation
, but how do you "not include" them?
Then I thought the best solution would be to use a specific product flavor dimension, but that changes quite a lot of things in the release process (mainly the output APK path) therefore I wasn't very confident making this change. I ended up going for this procedural solution which isn't very elegant but at least shouldn't break anything.
I'm open to changing the implementation to build types or flavors (and I'd even prefer it as it would make the OSS variant a first-class citizen), but I need help to make sure I don't break the release process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is done. I've used build flavors which definitely makes more sense. Needing help to update taskcluster.
|
||
import android.content.Context | ||
|
||
interface AdvertisingIDImpl : AdvertisingID { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a class instead of an interface?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. It's a bit more verbose but probably better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rolledback to an interface because otherwise detekt was complaining of an abstract class containing only abstract method (see UnncessaryAbstractClass). Tell me if you think it would be better off keeping a class and ignoring the warning using an annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, thanks for the quick review 👍 . I made most of the requested changes but some details are still unclear (see my responses).
app/build.gradle
Outdated
@@ -17,6 +17,8 @@ import org.mozilla.fenix.gradle.tasks.LintUnitTestRunner | |||
|
|||
import static org.gradle.api.tasks.testing.TestResult.ResultType | |||
|
|||
def useFreeImplementation = project.properties['org.mozilla.fenix.useFreeImplementation'].toBoolean() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my original intention, but wasn't sure how to exclude dependencies for a specific build type. Sure you can add new dependencies like debugImplementation
, but how do you "not include" them?
Then I thought the best solution would be to use a specific product flavor dimension, but that changes quite a lot of things in the release process (mainly the output APK path) therefore I wasn't very confident making this change. I ended up going for this procedural solution which isn't very elegant but at least shouldn't break anything.
I'm open to changing the implementation to build types or flavors (and I'd even prefer it as it would make the OSS variant a first-class citizen), but I need help to make sure I don't break the release process.
|
||
import android.content.Context | ||
|
||
interface AdvertisingIDImpl : AdvertisingID { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. It's a bit more verbose but probably better.
import android.net.Uri | ||
import java.util.UUID | ||
|
||
class LeanplumMetricsServiceImpl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First one is easy, the service is used in MetricController.create and discarded if the Telemetry flag is set to false. No change needed.
Since you can't include LeanplumMetricsService
in main sources because of the imports, you still need a dummy implementation somewhere at least to make the compiler happy when building the free variant. Or are you suggesting to defer this at runtime by using reflection? What am I missing?
|
||
class OssLicensesMenuImpl : OssLicensesMenu { | ||
override fun getIntent(context: Context?, title: String): Intent { | ||
// This menu shouldn't displayed on the free variant anyways. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I don't know why I thought it wasn't required for OSS software 🤐 . So I replaced Google's library with AboutLibraries which is the most popular FLOSS alternative I could find and it just looks better.
Note that I had to pin android gradle because AboutLibraries has gradle:4.0.0
which isn't compatible with Fenix yet (#13262). For the records, I quickly checked what were the blockers to upgrading the android gradle plugin and I found that the glean-gradle-plugin is incompatible: getBuildConfigPackageName()
now returns a Property
so you have to call get()
on it. Also, I also had to update the RepoMatching like this:
- const val comAndroid = "com\\.android\\..*"
+ const val comAndroid = "com\\.android(\\..+)?"
I don't think those two changes are sufficient to update because there are more subtle issues with the components, but at least these could easily be addressed in other PRs.
Out of curiosity, I also looked how the licenses menu worked in Fennec, and it turns out Fennec just opens about:license
, which doesn't list Android dependencies. We could fallback to this, but I don't think it's a fair solution.
719f2e7
to
5f3de6e
Compare
I've moved to using build flavors instead of a build flag and fixed tests for both flavors. As expected, taskcluster will have to be updated to run the OSS tests suite and produce the OSS apks. I'd appreciate some help as I don't know how to test this locally. |
I've tried to blindly update the taskcluster config, but it'll be hard to go further without being able to test. Please tell me there's anything I can do to get this PR to the next step. Thanks! (and thoughts for all the Mozilla employees who were laid off 😢) |
Yeah, challenging times. I'll get back to that PR. Thank you so far for all that work! 👍 |
This will be done in a separate PR: mozilla-mobile#13767
e76fe58
to
8d948bf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the confusion, I do think we want build flags for those (like in your initial PR) and not a separate flavor dimension. We just worked hard reducing all our dimensions to avoid an explosion of variants. :)
Overall I think the reason is that we want to be more fine-grained: "OSS" doesn't really capture it. For example Leanplum is OSS (code). But I understand you still want to exclude it for a fdroid build. Also lib-push
itself is OSS (but depends on a closed transitive dependency).
I think we want different build flags here for (disabling push, disabling leanplum (or marketing SDKs in general, disabling telemetry?). In some combination we may end up using those too in some of our builds (e.g. not all devices come with firebase push support).
Changing the build variants as a really loooong ripple effect on automation and other systems and I would like us to not get into this.. :)
@pocmo thanks for your response. Although build flavors are generally the intended way to do this, I can totally understand your reasoning. I'll bring back build flags then. |
Thank you! I am on PTO next week, so it may take a bit until can take another look. |
Enjoy yourself 😄 . |
I'll close this PR and make tinier, per-build flag PRs to make reviews easier. |
This PR adds an OSS build flavor allowing to build fenix without proprietary components, namely:
I didn't do the work for other SDKs that are open-source but promote closed-source tracking services (such as Adjust), as it is not strictly necessary to release fenix on F-Droid as far as I know.
Build the oss / non-oss flavor:
Simple check for proprietary dependencies:
So I guess it works.
I think this PR even closes #162 as the work of making fenix available on F-Droid will mostly be political after that.
Pull Request checklist
After merge
To download an APK when reviewing a PR:
ping @pocmo