• This repository has been archived on 13/Feb/2022
  • Stars
    star
    103
  • Rank 333,046 (Top 7 %)
  • Language
    Java
  • Created almost 10 years ago
  • Updated about 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Android library for executing tasks.

JobManager

An Android library that facilitates scheduling persistent jobs which are executed when their prerequisites have been met. Similar to Path's android-priority-queue.

Add as a gradle dependency, replacing ${latest_version} with the version currently available:

dependencies {
  compile 'org.whispersystems:jobmanager:${latest_version}'
}

The JobManager Way

Android apps often need to perform blocking operations. A messaging app might need to make REST API calls over a network, send SMS messages, download attachments, and interact with a database.

The standard Android way to do these things are with Services, AsyncTasks, or a dedicated Thread. However, some of an app's operations might need to wait until certain dependencies are available (such as a network connection), and some of the operations might need to be durable (complete even if the app restarts before they have a chance to run). The standard Android way can result in a lot of retry logic, timers for monitoring dependencies, and one-off code for making operations durable.

By contrast, the JobManager way allows operations to be broken up into Jobs. A Job represents a unit of work to be done, the prerequisites that need to be met (such as network access) before the work can execute, and the characteristics of the job (such as durable persistence).

Applications construct a JobManager at initialization time:

public class ApplicationContext extends Application {

  private JobManager jobManager;

  @Override
  public void onCreate() {
    initializeJobManager();
  }

  private void initializeJobManager() {
    this.jobManager = JobManager.newBuilder(this)
                                .withName("SampleJobManager")
                                .withConsumerThreads(5)
                                .build();
  }

  ...

}

This constructs a new JobManager with 5 consumer threads dedicated to executing Jobs. A Job looks like this:

public class SampleJob extends Job {

  public SampleJob() {
    super(JobParameters.newBuilder().create());
  }

  @Override
  public onAdded() {
    // Called after the Job has been added to the queue.
  }

  @Override
  public void onRun() {
    // Here's where we execute our work.
    Log.w("SampleJob", "Hello, world!");
  }

  @Override
  public void onCanceled() {
    // This would be called if the job had failed.
  }

  @Override
  public boolean onShouldRetry(Exception exception) {
   // Called if onRun() had thrown an exception to determine whether
   // onRun() should be called again.
   return false;
  }
}

A Job is scheduled simply by adding it to the JobManager:

  this.jobManager.add(new SampleJob());

Persistence

To create durable Jobs, the JobManager needs to be given an interface responsible for serializing and deserializing Job objects. A JavaJobSerializer is included with JobManager that uses Java Serialization, but you can specify your own serializer if you wish:

public class ApplicationContext extends Application {

  private JobManager jobManager;

  @Override
  public void onCreate() {
    initializeJobManager();
  }

  private void initializeJobManager() {
    this.jobManager = JobManager.newBuilder(this)
                                .withName("SampleJobManager")
                                .withConsumerThreads(5)
                                .withJobSerializer(new JavaJobSerializer())
                                .build();
  }

  ...

}

The Job simply needs to declare itself as durable when constructed:

public class SampleJob extends Job {

  public SampleJob() {
    super(JobParameters.newBuilder()
                       .withPersistence()
                       .create());
  }

  ...

Persistent jobs that are enqueued will be serialized to disk to ensure that they run even if the App restarts first. A Job's onAdded() method is called after the commit to disk is complete.

Requirements

A Job might have certain requirements that need to be met before it can run. A requirement is represented by the Requirement interface. Each Requirement must also have a corresponding RequirementProvider that is registered with the JobManager.

A Requirement tells you whether it is present when queried, while a RequirementProvider broadcasts to a listener when a Requirement's status might have changed. Requirement is attached to Job, while RequirementProvider is attached to JobManager.

One common Requirement a Job might depend on is the presence of network connectivity. A NetworkRequirement is bundled with JobManager:

public class ApplicationContext extends Application {

  private JobManager jobManager;

  @Override
  public void onCreate() {
    initializeJobManager();
  }

  private void initializeJobManager() {
    this.jobManager = JobManager.newBuilder(this)
                                .withName("SampleJobManager")
                                .withConsumerThreads(5)
                                .withJobSerializer(new JavaJobSerializer())
                                .withRequirementProviders(new NetworkRequirementProvider(this))
                                .build();
  }

  ...

}

The Job declares itself as having a Requirement when constructed:

public class SampleJob extends Job {

  public SampleJob(Context context) {
    super(JobParameters.newBuilder()
                       .withPersistence()
                       .withRequirement(new NetworkRequirement(context))
                       .create());
  }

  ...

Dependency Injection

It is possible that Jobs (and Requirements) might require dependency injection. A simple example is Context, which many Jobs might require, but can't be persisted to disk for durable Jobs. Or maybe Jobs require more complex DI through libraries such as Dagger.

JobManager has an extremely primitive DI mechanism strictly for injecting Context objects into Jobs and Requirements after they're deserialized, and includes support for plugging in more complex DI systems such as Dagger.

The JobManager Context injection works by having your Job and/or Requirement implement the ContextDependent interface. Jobs and Requirements implementing that interface will get a setContext(Context context) call immediately after the persistent Job or Requirement is deserialized.

To plugin a more complex DI mechanism, simply pass an instance of the DependencyInjector interface to the JobManager:

public class ApplicationContext extends Application implements DependencyInjector {

  private JobManager jobManager;

  @Override
  public void onCreate() {
    initializeJobManager();
  }

  private void initializeJobManager() {
    this.jobManager = JobManager.newBuilder(this)
                                .withName("SampleJobManager")
                                .withConsumerThreads(5)
                                .withJobSerializer(new JavaJobSerializer())
                                .withRequirementProviders(new NetworkRequirementProvider(this))
                                .withDependencyInjector(this)
                                .build();
  }

  @Override
  public void injectDependencies(Object object) {
    // And here we do our DI magic.
  }

  ...

}

injectDependencies(Object object) will be called for a Job before the job's onAdded() method is called, or after a persistent job is deserialized.

License

Copyright 2014 Open Whisper Systems

Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html

More Repositories

1

Signal-Android

A private messenger for Android.
Kotlin
25,358
star
2

Signal-Desktop

A private messenger for Windows, macOS, and Linux.
TypeScript
14,441
star
3

Signal-iOS

A private messenger for iOS.
Swift
10,703
star
4

Signal-Server

Server supporting the Signal Private Messenger applications on Android, Desktop, and iOS
Java
9,071
star
5

libsignal

Home to the Signal Protocol as well as other cryptographic primitives which make Signal possible.
Rust
3,345
star
6

libsignal-protocol-javascript

This library is no longer maintained. libsignal-protocol-javascript was an implementation of the Signal Protocol, written in JavaScript. It has been replaced by libsignal-client’s typesafe TypeScript API.
JavaScript
1,954
star
7

libsignal-protocol-java

Java
1,823
star
8

libsignal-protocol-c

C
1,404
star
9

BitHub

BTC + BitHub = An experiment in funding privacy OSS.
Java
997
star
10

Signal-TLS-Proxy

Shell
830
star
11

libsignal-service-java

A Java/Android library for communicating with the Signal messaging service.
Java
584
star
12

ringrtc

Rust
538
star
13

Signal-Calling-Service

Forwards media from 1 group call device to N group call devices.
Rust
412
star
14

Flock

Private contact and calendar sync for Android.
Java
358
star
15

ContactDiscoveryService

C
279
star
16

SecureValueRecovery

Rust
274
star
17

curve25519-java

Pure Java and JNI backed Curve25519 implementation.
C
230
star
18

gradle-witness

A gradle plugin that enables static verification for remote dependencies.
Groovy
229
star
19

SignalProtocolKit

This library is no longer maintained. SignalProtocolKit was an implementation of the Signal Protocol, written in Objective-C. It has been replaced by libsignal-client’s type safe Swift API.
Objective-C
213
star
20

webrtc

C++
140
star
21

PushServer

A microservice for communicating with push gateways.
Java
115
star
22

WhisperYAFFS

Encrypted Filesystem Support For YAFFS2
C
104
star
23

WebSocket-Resources

A Dropwizard library that lets you use Jersey-style Resources over WebSockets
Java
91
star
24

better-sqlite3

C++
76
star
25

SignalServiceKit

SignalServiceKit has moved to Signal-iOS. See README.md for details.
Objective-C
68
star
26

libwebrtc-android

Android WebRTC Packages
Java
60
star
27

Signal-Pods

Pods dependency tracker for Signal-iOS
C
57
star
28

signal-ringrtc-node

TypeScript
50
star
29

gcm-sender-async

Asynchronous Google Cloud Messaging (GCM) Library
Java
48
star
30

zkgroup

41
star
31

curve25519-dalek

Rust
37
star
32

SecureValueRecovery2

C++
37
star
33

libsignal-protocol-rust

Rust
37
star
34

Argon2

Java
36
star
35

Signal-Design

A place to archive design assets used by Signal.
35
star
36

SignalCoreKit

Swift
34
star
37

storage-service

Java
34
star
38

signal-webrtc-ios

Python
33
star
39

Signal-FTS5-Extension

A FTS5 extension for signal_tokenizer.
Rust
32
star
40

ContactDiscoveryService-Icelake

C
31
star
41

maven

27
star
42

libpastelog

Java
27
star
43

tus-server

An implementation of the TUS server protocol for resumable uploads
TypeScript
25
star
44

Mock-Signal-Server

TypeScript
24
star
45

registration-service

Registration Service for Signal
Java
23
star
46

dropwizard-simpleauth

Dropwizard library for simple @Auth annotations that support multiple types
Java
22
star
47

CLAServer

GitHub Integration for managing CLA signatures
Java
22
star
48

mio

Rust
20
star
49

AES-GCM-Provider

A BoringSSL-backed AES-GCM provider for Android with support for "incremental" encryption/decryption
Java
20
star
50

libaxolotl-j2me

Axolotl J2ME
Java
17
star
51

Signal-Art-Creator

Sticker Pack Creator Web App
TypeScript
17
star
52

signal-webrtc-ios-artifacts

Objective-C
17
star
53

SQLCipherVsSharedData

Demo Project to demonstrate a bug in SQLCipher
Objective-C
15
star
54

dropwizard-wavefront

Dropwizard Metrics Reporter For Wavefront
Java
14
star
55

sgx_common

Rust
14
star
56

emoji-search-index

Static assets used for to generate a search index for emoji within Signal.
12
star
57

Signal-Carthage

Objective-C
12
star
58

SignalMetadataKit

Swift
12
star
59

libmobilecoin-ios-artifacts

Swift
12
star
60

libsignal-client-node

11
star
61

redis-dispatch

Java
11
star
62

sqlcipher

C
11
star
63

libsignal-metadata-java

Java
11
star
64

mp4san

A Rust MP4 format sanitizer
Rust
10
star
65

poksho

9
star
66

AccountStream

Java
8
star
67

signal-zkgroup-node

TypeScript
8
star
68

s3-upload-maven-plugin

Maven plugin to upload files to s3
Java
7
star
69

jekyll-simple-i18n

Ruby
7
star
70

HsmEnclave

HSM-backed remote-attestable enclave.
C
5
star
71

sqlcipher-android

A light fork of https://github.com/sqlcipher/sqlcipher-android
C
5
star
72

storage-manager

Manage objects inside a cdn
TypeScript
5
star
73

libsignal-ffi

Rust
4
star
74

partial-default

Provides PartialDefault, a Rust trait similar to Default but with fewer guarantees
Rust
4
star
75

signal-zkgroup-swift

Swift
4
star
76

libsignal-protocol-swift

Swift
2
star
77

Signal-Message-Backup-Tests

Signal Message Backup shared client integration test cases
Rust
2
star
78

libmobilecoin-apple-artifacts

C
2
star
79

Signal-Sqlcipher-Extension

A sqlcipher extension for crypto provider.
Rust
1
star