refactor: performance improvements in batch message processing, synchronized cache access and audible message notifications.

Increase audible timeout on DefaultMessageNotifier.java, don't send in-thread notification based on last audible notification.

Create a batch message receive job to handle up to 20 chunked messages at a time per job instead of singular or open group poll amount

Remove synchronized access to recipient cache and replace with a concurrent cache that's lock free from perf tracing monitor contention
This commit is contained in:
Harris 2021-09-29 15:29:24 +10:00
parent 5a290ddf68
commit e036344c76
13 changed files with 700 additions and 52 deletions

View File

@ -97,7 +97,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
private static final int SUMMARY_NOTIFICATION_ID = 1338; private static final int SUMMARY_NOTIFICATION_ID = 1338;
private static final int PENDING_MESSAGES_ID = 1111; private static final int PENDING_MESSAGES_ID = 1111;
private static final String NOTIFICATION_GROUP = "messages"; private static final String NOTIFICATION_GROUP = "messages";
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2); private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(5);
private static final long DESKTOP_ACTIVITY_PERIOD = TimeUnit.MINUTES.toMillis(1); private static final long DESKTOP_ACTIVITY_PERIOD = TimeUnit.MINUTES.toMillis(1);
private volatile static long visibleThread = -1; private volatile static long visibleThread = -1;
@ -440,9 +440,12 @@ public class DefaultMessageNotifier implements MessageNotifier {
private void sendInThreadNotification(Context context, Recipient recipient) { private void sendInThreadNotification(Context context, Recipient recipient) {
if (!TextSecurePreferences.isInThreadNotifications(context) || if (!TextSecurePreferences.isInThreadNotifications(context) ||
ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL) ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL ||
(System.currentTimeMillis() - lastAudibleNotification) < MIN_AUDIBLE_PERIOD_MILLIS)
{ {
return; return;
} else {
lastAudibleNotification = System.currentTimeMillis();
} }
Uri uri = null; Uri uri = null;

View File

@ -5,7 +5,6 @@ import android.net.Uri
import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.Job import org.session.libsession.messaging.jobs.Job
import org.session.libsession.messaging.jobs.MessageReceiveJob
import org.session.libsession.messaging.jobs.MessageSendJob import org.session.libsession.messaging.jobs.MessageSendJob
import org.session.libsession.messaging.messages.control.ConfigurationMessage import org.session.libsession.messaging.messages.control.ConfigurationMessage
import org.session.libsession.messaging.messages.visible.Attachment import org.session.libsession.messaging.messages.visible.Attachment
@ -43,7 +42,7 @@ interface StorageProtocol {
fun getAllPendingJobs(type: String): Map<String,Job?> fun getAllPendingJobs(type: String): Map<String,Job?>
fun getAttachmentUploadJob(attachmentID: Long): AttachmentUploadJob? fun getAttachmentUploadJob(attachmentID: Long): AttachmentUploadJob?
fun getMessageSendJob(messageSendJobID: String): MessageSendJob? fun getMessageSendJob(messageSendJobID: String): MessageSendJob?
fun getMessageReceiveJob(messageReceiveJobID: String): MessageReceiveJob? fun getMessageReceiveJob(messageReceiveJobID: String): Job?
fun resumeMessageSendJobIfNeeded(messageSendJobID: String) fun resumeMessageSendJobIfNeeded(messageSendJobID: String)
fun isJobCanceled(job: Job): Boolean fun isJobCanceled(job: Job): Boolean

View File

@ -0,0 +1,120 @@
package org.session.libsession.messaging.jobs
import com.google.protobuf.ByteString
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.task
import org.session.libsession.messaging.sending_receiving.MessageReceiver
import org.session.libsession.messaging.sending_receiving.handle
import org.session.libsession.messaging.utilities.Data
import org.session.libsignal.protos.UtilProtos
import org.session.libsignal.utilities.Log
data class MessageReceiveParameters(
val data: ByteArray,
val serverHash: String? = null,
val openGroupMessageServerID: Long? = null
)
class BatchMessageReceiveJob(
val messages: List<MessageReceiveParameters>,
val openGroupID: String? = null
) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
override val maxFailureCount: Int = 10
// Failure Exceptions must be retryable if they're a MessageReceiver.Error
val failures = mutableListOf<MessageReceiveParameters>()
companion object {
const val TAG = "BatchMessageReceiveJob"
const val KEY = "BatchMessageReceiveJob"
// Keys used for database storage
private val NUM_MESSAGES_KEY = "numMessages"
private val DATA_KEY = "data"
private val SERVER_HASH_KEY = "serverHash"
private val OPEN_GROUP_MESSAGE_SERVER_ID_KEY = "openGroupMessageServerID"
private val OPEN_GROUP_ID_KEY = "open_group_id"
}
override fun execute() {
executeAsync().get()
}
fun executeAsync(): Promise<Unit, Exception> {
return task {
messages.forEach { messageParameters ->
val (data, serverHash, openGroupMessageServerID) = messageParameters
try {
val (message, proto) = MessageReceiver.parse(data, openGroupMessageServerID)
message.serverHash = serverHash
MessageReceiver.handle(message, proto, this.openGroupID)
} catch (e: Exception) {
Log.e(TAG, "Couldn't receive message.", e)
if (e is MessageReceiver.Error && !e.isRetryable) {
Log.e(TAG, "Message failed permanently",e)
} else {
Log.e(TAG, "Message failed",e)
failures += messageParameters
}
}
}
if (failures.isEmpty()) {
handleSuccess()
} else {
handleFailure()
}
}
}
private fun handleSuccess() {
this.delegate?.handleJobSucceeded(this)
}
private fun handleFailure() {
this.delegate?.handleJobFailed(this, Exception("One or more jobs resulted in failure"))
}
override fun serialize(): Data {
val arraySize = messages.size
val dataArrays = UtilProtos.ByteArrayList.newBuilder()
.addAllContent(messages.map(MessageReceiveParameters::data).map(ByteString::copyFrom))
.build()
val serverHashes = messages.map { it.serverHash.orEmpty() }
val openGroupServerIds = messages.map { it.openGroupMessageServerID ?: -1L }
return Data.Builder()
.putInt(NUM_MESSAGES_KEY, arraySize)
.putByteArray(DATA_KEY, dataArrays.toByteArray())
.putString(OPEN_GROUP_ID_KEY, openGroupID)
.putLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY, openGroupServerIds.toLongArray())
.putStringArray(SERVER_HASH_KEY, serverHashes.toTypedArray())
.build()
}
override fun getFactoryKey(): String = KEY
class Factory : Job.Factory<BatchMessageReceiveJob> {
override fun create(data: Data): BatchMessageReceiveJob {
val numMessages = data.getInt(NUM_MESSAGES_KEY)
val dataArrays = data.getByteArray(DATA_KEY)
val contents =
UtilProtos.ByteArrayList.parseFrom(dataArrays).contentList.map(ByteString::toByteArray)
val serverHashes =
if (data.hasStringArray(SERVER_HASH_KEY)) data.getStringArray(SERVER_HASH_KEY) else arrayOf()
val openGroupMessageServerIDs = data.getLongArray(OPEN_GROUP_MESSAGE_SERVER_ID_KEY)
val openGroupID = data.getStringOrDefault(OPEN_GROUP_ID_KEY, null)
val parameters = (0 until numMessages).map { index ->
val data = contents[index]
val serverHash = serverHashes[index].let { if (it.isEmpty()) null else it }
val serverId = openGroupMessageServerIDs[index].let { if (it == -1L) null else it }
MessageReceiveParameters(data, serverHash, serverId)
}
return BatchMessageReceiveJob(parameters, openGroupID)
}
}
}

View File

@ -5,7 +5,6 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import java.lang.IllegalStateException
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -51,7 +50,7 @@ class JobQueue : JobDelegate {
when (job) { when (job) {
is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob -> txQueue.send(job) is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob -> txQueue.send(job)
is AttachmentDownloadJob -> attachmentQueue.send(job) is AttachmentDownloadJob -> attachmentQueue.send(job)
is MessageReceiveJob, is TrimThreadJob -> rxQueue.send(job) is MessageReceiveJob, is BatchMessageReceiveJob, is TrimThreadJob -> rxQueue.send(job)
else -> throw IllegalStateException("Unexpected job type.") else -> throw IllegalStateException("Unexpected job type.")
} }
} }
@ -128,7 +127,8 @@ class JobQueue : JobDelegate {
AttachmentDownloadJob.KEY, AttachmentDownloadJob.KEY,
MessageReceiveJob.KEY, MessageReceiveJob.KEY,
MessageSendJob.KEY, MessageSendJob.KEY,
NotifyPNServerJob.KEY NotifyPNServerJob.KEY,
BatchMessageReceiveJob.KEY
) )
allJobTypes.forEach { type -> allJobTypes.forEach { type ->
resumePendingJobs(type) resumePendingJobs(type)
@ -152,6 +152,11 @@ class JobQueue : JobDelegate {
Log.i("Loki", "Message send job waiting for attachment upload to finish.") Log.i("Loki", "Message send job waiting for attachment upload to finish.")
return return
} }
// Batch message receive job, re-queue non-permanently failed jobs
if (job is BatchMessageReceiveJob) {
val replacementParameters = job.failures
}
// Regular job failure // Regular job failure
job.failureCount += 1 job.failureCount += 1
if (job.failureCount >= job.maxFailureCount) { if (job.failureCount >= job.maxFailureCount) {

View File

@ -17,8 +17,6 @@ class MessageReceiveJob(val data: ByteArray, val serverHash: String? = null, val
val TAG = MessageReceiveJob::class.simpleName val TAG = MessageReceiveJob::class.simpleName
val KEY: String = "MessageReceiveJob" val KEY: String = "MessageReceiveJob"
private val RECEIVE_LOCK = Object()
// Keys used for database storage // Keys used for database storage
private val DATA_KEY = "data" private val DATA_KEY = "data"
private val SERVER_HASH_KEY = "serverHash" private val SERVER_HASH_KEY = "serverHash"
@ -36,9 +34,7 @@ class MessageReceiveJob(val data: ByteArray, val serverHash: String? = null, val
val isRetry: Boolean = failureCount != 0 val isRetry: Boolean = failureCount != 0
val (message, proto) = MessageReceiver.parse(this.data, this.openGroupMessageServerID) val (message, proto) = MessageReceiver.parse(this.data, this.openGroupMessageServerID)
message.serverHash = serverHash message.serverHash = serverHash
synchronized(RECEIVE_LOCK) { // FIXME: Do we need this? MessageReceiver.handle(message, proto, this.openGroupID)
MessageReceiver.handle(message, proto, this.openGroupID)
}
this.handleSuccess() this.handleSuccess()
deferred.resolve(Unit) deferred.resolve(Unit)
} catch (e: Exception) { } catch (e: Exception) {
@ -82,11 +78,15 @@ class MessageReceiveJob(val data: ByteArray, val serverHash: String? = null, val
class Factory: Job.Factory<MessageReceiveJob> { class Factory: Job.Factory<MessageReceiveJob> {
override fun create(data: Data): MessageReceiveJob { override fun create(data: Data): MessageReceiveJob {
val dataArray = data.getByteArray(DATA_KEY)
val serverHash = data.getStringOrDefault(SERVER_HASH_KEY, null)
val openGroupMessageServerID = data.getLongOrDefault(OPEN_GROUP_MESSAGE_SERVER_ID_KEY, -1).let { if (it == -1L) null else it }
val openGroupID = data.getStringOrDefault(OPEN_GROUP_ID_KEY, null)
return MessageReceiveJob( return MessageReceiveJob(
data.getByteArray(DATA_KEY), dataArray,
data.getString(SERVER_HASH_KEY), serverHash,
data.getLong(OPEN_GROUP_MESSAGE_SERVER_ID_KEY), openGroupMessageServerID,
data.getString(OPEN_GROUP_ID_KEY) openGroupID
) )
} }
} }

View File

@ -11,7 +11,8 @@ class SessionJobManagerFactories {
MessageReceiveJob.KEY to MessageReceiveJob.Factory(), MessageReceiveJob.KEY to MessageReceiveJob.Factory(),
MessageSendJob.KEY to MessageSendJob.Factory(), MessageSendJob.KEY to MessageSendJob.Factory(),
NotifyPNServerJob.KEY to NotifyPNServerJob.Factory(), NotifyPNServerJob.KEY to NotifyPNServerJob.Factory(),
TrimThreadJob.KEY to TrimThreadJob.Factory() TrimThreadJob.KEY to TrimThreadJob.Factory(),
BatchMessageReceiveJob.KEY to BatchMessageReceiveJob.Factory()
) )
} }
} }

View File

@ -3,17 +3,12 @@ package org.session.libsession.messaging.sending_receiving.pollers
import nl.komponents.kovenant.Promise import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.map import nl.komponents.kovenant.functional.map
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.jobs.*
import org.session.libsession.messaging.jobs.MessageReceiveJob
import org.session.libsession.messaging.jobs.TrimThreadJob
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupMessageV2 import org.session.libsession.messaging.open_groups.OpenGroupMessageV2
import org.session.libsession.messaging.sending_receiving.MessageReceiver
import org.session.libsession.messaging.sending_receiving.handle
import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address
import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.GroupUtil
import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.successBackground import org.session.libsignal.utilities.successBackground
import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture import java.util.concurrent.ScheduledFuture
@ -27,7 +22,7 @@ class OpenGroupPollerV2(private val server: String, private val executorService:
private var future: ScheduledFuture<*>? = null private var future: ScheduledFuture<*>? = null
companion object { companion object {
private val pollInterval: Long = 4 * 1000 private const val pollInterval: Long = 4000L
const val maxInactivityPeriod = 14 * 24 * 60 * 60 * 1000 const val maxInactivityPeriod = 14 * 24 * 60 * 60 * 1000
} }
@ -66,21 +61,22 @@ class OpenGroupPollerV2(private val server: String, private val executorService:
val threadId = storage.getThreadId(Address.fromSerialized(groupID)) ?: -1 val threadId = storage.getThreadId(Address.fromSerialized(groupID)) ?: -1
val threadExists = threadId >= 0 val threadExists = threadId >= 0
if (!hasStarted || !threadExists) { return } if (!hasStarted || !threadExists) { return }
messages.sortedBy { it.serverID!! }.forEach { message -> val envelopes = messages.sortedBy { it.serverID!! }.map { message ->
try { val senderPublicKey = message.sender!!
val senderPublicKey = message.sender!! val builder = SignalServiceProtos.Envelope.newBuilder()
val builder = SignalServiceProtos.Envelope.newBuilder() builder.type = SignalServiceProtos.Envelope.Type.SESSION_MESSAGE
builder.type = SignalServiceProtos.Envelope.Type.SESSION_MESSAGE builder.source = senderPublicKey
builder.source = senderPublicKey builder.sourceDevice = 1
builder.sourceDevice = 1 builder.content = message.toProto().toByteString()
builder.content = message.toProto().toByteString() builder.timestamp = message.sentTimestamp
builder.timestamp = message.sentTimestamp builder.build() to message.serverID
val envelope = builder.build() }
val (parsedMessage, content) = MessageReceiver.parse(envelope.toByteArray(), message.serverID)
MessageReceiver.handle(parsedMessage, content, openGroupID) envelopes.chunked(20).forEach { list ->
} catch (e: Exception) { val parameters = list.map { (message, serverId) ->
Log.e("Loki", "Exception parsing message", e) MessageReceiveParameters(message.toByteArray(), openGroupMessageServerID = serverId)
} }
JobQueue.shared.add(BatchMessageReceiveJob(parameters, openGroupID))
} }
val currentLastMessageServerID = storage.getLastMessageServerID(room, server) ?: 0 val currentLastMessageServerID = storage.getLastMessageServerID(room, server) ?: 0
@ -88,9 +84,6 @@ class OpenGroupPollerV2(private val server: String, private val executorService:
if (actualMax > 0) { if (actualMax > 0) {
storage.setLastMessageServerID(room, server, actualMax) storage.setLastMessageServerID(room, server, actualMax)
} }
if (messages.isNotEmpty()) {
JobQueue.shared.add(TrimThreadJob(threadId))
}
} }
private fun handleDeletedMessages(room: String, openGroupID: String, deletions: List<OpenGroupAPIV2.MessageDeletion>) { private fun handleDeletedMessages(room: String, openGroupID: String, deletions: List<OpenGroupAPIV2.MessageDeletion>) {

View File

@ -3,12 +3,13 @@ package org.session.libsession.messaging.sending_receiving.pollers
import nl.komponents.kovenant.* import nl.komponents.kovenant.*
import nl.komponents.kovenant.functional.bind import nl.komponents.kovenant.functional.bind
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.BatchMessageReceiveJob
import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageReceiveJob import org.session.libsession.messaging.jobs.MessageReceiveParameters
import org.session.libsession.snode.SnodeAPI import org.session.libsession.snode.SnodeAPI
import org.session.libsession.snode.SnodeModule import org.session.libsession.snode.SnodeModule
import org.session.libsignal.utilities.Snode
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.Snode
import java.security.SecureRandom import java.security.SecureRandom
import java.util.* import java.util.*
@ -91,10 +92,14 @@ class Poller {
task { Unit } // The long polling connection has been canceled; don't recurse task { Unit } // The long polling connection has been canceled; don't recurse
} else { } else {
val messages = SnodeAPI.parseRawMessagesResponse(rawResponse, snode, userPublicKey) val messages = SnodeAPI.parseRawMessagesResponse(rawResponse, snode, userPublicKey)
messages.forEach { (envelope, serverHash) -> val parameters = messages.map { (envelope, serverHash) ->
val job = MessageReceiveJob(envelope.toByteArray(), serverHash) MessageReceiveParameters(envelope.toByteArray(), serverHash = serverHash)
}
parameters.chunked(20).forEach { chunk ->
val job = BatchMessageReceiveJob(chunk)
JobQueue.shared.add(job) JobQueue.shared.add(job)
} }
poll(snode, deferred) poll(snode, deferred)
} }
} }

View File

@ -363,7 +363,7 @@ object TextSecurePreferences {
@JvmStatic @JvmStatic
fun getDirectCaptureCameraId(context: Context): Int { fun getDirectCaptureCameraId(context: Context): Int {
return getIntegerPreference(context, DIRECT_CAPTURE_CAMERA_ID, Camera.CameraInfo.CAMERA_FACING_FRONT) return getIntegerPreference(context, DIRECT_CAPTURE_CAMERA_ID, Camera.CameraInfo.CAMERA_FACING_BACK)
} }
@JvmStatic @JvmStatic

View File

@ -29,7 +29,6 @@ import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.GroupRecord; import org.session.libsession.utilities.GroupRecord;
import org.session.libsession.utilities.ListenableFutureTask; import org.session.libsession.utilities.ListenableFutureTask;
import org.session.libsession.utilities.MaterialColor; import org.session.libsession.utilities.MaterialColor;
import org.session.libsession.utilities.SoftHashMap;
import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Util; import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.recipients.Recipient.RecipientSettings; import org.session.libsession.utilities.recipients.Recipient.RecipientSettings;
@ -43,6 +42,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
class RecipientProvider { class RecipientProvider {
@ -222,17 +222,17 @@ class RecipientProvider {
private static class RecipientCache { private static class RecipientCache {
private final Map<Address,Recipient> cache = new SoftHashMap<>(1000); private final Map<Address,Recipient> cache = new ConcurrentHashMap<>(1000);
public synchronized Recipient get(Address address) { public Recipient get(Address address) {
return cache.get(address); return cache.get(address);
} }
public synchronized void set(Address address, Recipient recipient) { public void set(Address address, Recipient recipient) {
cache.put(address, recipient); cache.put(address, recipient);
} }
public synchronized boolean remove(Address address) { public boolean remove(Address address) {
return cache.remove(address) != null; return cache.remove(address) != null;
} }

View File

@ -1,3 +1,3 @@
all: all:
protoc25 --java_out=../src/main/java/ SignalService.proto WebSocketResources.proto protoc25 --java_out=../src/main/java/ SignalService.proto WebSocketResources.proto Utils.proto

View File

@ -0,0 +1,10 @@
syntax = "proto2";
package signalservice;
option java_package = "org.session.libsignal.protos";
option java_outer_classname = "UtilProtos";
message ByteArrayList {
repeated bytes content = 1;
}

View File

@ -0,0 +1,512 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: Utils.proto
package org.session.libsignal.protos;
public final class UtilProtos {
private UtilProtos() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
}
public interface ByteArrayListOrBuilder
extends com.google.protobuf.MessageOrBuilder {
// repeated bytes content = 1;
/**
* <code>repeated bytes content = 1;</code>
*/
java.util.List<com.google.protobuf.ByteString> getContentList();
/**
* <code>repeated bytes content = 1;</code>
*/
int getContentCount();
/**
* <code>repeated bytes content = 1;</code>
*/
com.google.protobuf.ByteString getContent(int index);
}
/**
* Protobuf type {@code signalservice.ByteArrayList}
*/
public static final class ByteArrayList extends
com.google.protobuf.GeneratedMessage
implements ByteArrayListOrBuilder {
// Use ByteArrayList.newBuilder() to construct.
private ByteArrayList(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
super(builder);
this.unknownFields = builder.getUnknownFields();
}
private ByteArrayList(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
private static final ByteArrayList defaultInstance;
public static ByteArrayList getDefaultInstance() {
return defaultInstance;
}
public ByteArrayList getDefaultInstanceForType() {
return defaultInstance;
}
private final com.google.protobuf.UnknownFieldSet unknownFields;
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private ByteArrayList(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
initFields();
int mutable_bitField0_ = 0;
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
default: {
if (!parseUnknownField(input, unknownFields,
extensionRegistry, tag)) {
done = true;
}
break;
}
case 10: {
if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
content_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
mutable_bitField0_ |= 0x00000001;
}
content_.add(input.readBytes());
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e.getMessage()).setUnfinishedMessage(this);
} finally {
if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
content_ = java.util.Collections.unmodifiableList(content_);
}
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return org.session.libsignal.protos.UtilProtos.internal_static_signalservice_ByteArrayList_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return org.session.libsignal.protos.UtilProtos.internal_static_signalservice_ByteArrayList_fieldAccessorTable
.ensureFieldAccessorsInitialized(
org.session.libsignal.protos.UtilProtos.ByteArrayList.class, org.session.libsignal.protos.UtilProtos.ByteArrayList.Builder.class);
}
public static com.google.protobuf.Parser<ByteArrayList> PARSER =
new com.google.protobuf.AbstractParser<ByteArrayList>() {
public ByteArrayList parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new ByteArrayList(input, extensionRegistry);
}
};
@java.lang.Override
public com.google.protobuf.Parser<ByteArrayList> getParserForType() {
return PARSER;
}
// repeated bytes content = 1;
public static final int CONTENT_FIELD_NUMBER = 1;
private java.util.List<com.google.protobuf.ByteString> content_;
/**
* <code>repeated bytes content = 1;</code>
*/
public java.util.List<com.google.protobuf.ByteString>
getContentList() {
return content_;
}
/**
* <code>repeated bytes content = 1;</code>
*/
public int getContentCount() {
return content_.size();
}
/**
* <code>repeated bytes content = 1;</code>
*/
public com.google.protobuf.ByteString getContent(int index) {
return content_.get(index);
}
private void initFields() {
content_ = java.util.Collections.emptyList();
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized != -1) return isInitialized == 1;
memoizedIsInitialized = 1;
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
getSerializedSize();
for (int i = 0; i < content_.size(); i++) {
output.writeBytes(1, content_.get(i));
}
getUnknownFields().writeTo(output);
}
private int memoizedSerializedSize = -1;
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
{
int dataSize = 0;
for (int i = 0; i < content_.size(); i++) {
dataSize += com.google.protobuf.CodedOutputStream
.computeBytesSizeNoTag(content_.get(i));
}
size += dataSize;
size += 1 * getContentList().size();
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
}
private static final long serialVersionUID = 0L;
@java.lang.Override
protected java.lang.Object writeReplace()
throws java.io.ObjectStreamException {
return super.writeReplace();
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(java.io.InputStream input)
throws java.io.IOException {
return PARSER.parseFrom(input);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return PARSER.parseFrom(input, extensionRegistry);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return PARSER.parseDelimitedFrom(input);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return PARSER.parseDelimitedFrom(input, extensionRegistry);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return PARSER.parseFrom(input);
}
public static org.session.libsignal.protos.UtilProtos.ByteArrayList parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return PARSER.parseFrom(input, extensionRegistry);
}
public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder(org.session.libsignal.protos.UtilProtos.ByteArrayList prototype) {
return newBuilder().mergeFrom(prototype);
}
public Builder toBuilder() { return newBuilder(this); }
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* Protobuf type {@code signalservice.ByteArrayList}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder>
implements org.session.libsignal.protos.UtilProtos.ByteArrayListOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return org.session.libsignal.protos.UtilProtos.internal_static_signalservice_ByteArrayList_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return org.session.libsignal.protos.UtilProtos.internal_static_signalservice_ByteArrayList_fieldAccessorTable
.ensureFieldAccessorsInitialized(
org.session.libsignal.protos.UtilProtos.ByteArrayList.class, org.session.libsignal.protos.UtilProtos.ByteArrayList.Builder.class);
}
// Construct using org.session.libsignal.protos.UtilProtos.ByteArrayList.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
}
}
private static Builder create() {
return new Builder();
}
public Builder clear() {
super.clear();
content_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000001);
return this;
}
public Builder clone() {
return create().mergeFrom(buildPartial());
}
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return org.session.libsignal.protos.UtilProtos.internal_static_signalservice_ByteArrayList_descriptor;
}
public org.session.libsignal.protos.UtilProtos.ByteArrayList getDefaultInstanceForType() {
return org.session.libsignal.protos.UtilProtos.ByteArrayList.getDefaultInstance();
}
public org.session.libsignal.protos.UtilProtos.ByteArrayList build() {
org.session.libsignal.protos.UtilProtos.ByteArrayList result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
public org.session.libsignal.protos.UtilProtos.ByteArrayList buildPartial() {
org.session.libsignal.protos.UtilProtos.ByteArrayList result = new org.session.libsignal.protos.UtilProtos.ByteArrayList(this);
int from_bitField0_ = bitField0_;
if (((bitField0_ & 0x00000001) == 0x00000001)) {
content_ = java.util.Collections.unmodifiableList(content_);
bitField0_ = (bitField0_ & ~0x00000001);
}
result.content_ = content_;
onBuilt();
return result;
}
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof org.session.libsignal.protos.UtilProtos.ByteArrayList) {
return mergeFrom((org.session.libsignal.protos.UtilProtos.ByteArrayList)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(org.session.libsignal.protos.UtilProtos.ByteArrayList other) {
if (other == org.session.libsignal.protos.UtilProtos.ByteArrayList.getDefaultInstance()) return this;
if (!other.content_.isEmpty()) {
if (content_.isEmpty()) {
content_ = other.content_;
bitField0_ = (bitField0_ & ~0x00000001);
} else {
ensureContentIsMutable();
content_.addAll(other.content_);
}
onChanged();
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
public final boolean isInitialized() {
return true;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
org.session.libsignal.protos.UtilProtos.ByteArrayList parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (org.session.libsignal.protos.UtilProtos.ByteArrayList) e.getUnfinishedMessage();
throw e;
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private int bitField0_;
// repeated bytes content = 1;
private java.util.List<com.google.protobuf.ByteString> content_ = java.util.Collections.emptyList();
private void ensureContentIsMutable() {
if (!((bitField0_ & 0x00000001) == 0x00000001)) {
content_ = new java.util.ArrayList<com.google.protobuf.ByteString>(content_);
bitField0_ |= 0x00000001;
}
}
/**
* <code>repeated bytes content = 1;</code>
*/
public java.util.List<com.google.protobuf.ByteString>
getContentList() {
return java.util.Collections.unmodifiableList(content_);
}
/**
* <code>repeated bytes content = 1;</code>
*/
public int getContentCount() {
return content_.size();
}
/**
* <code>repeated bytes content = 1;</code>
*/
public com.google.protobuf.ByteString getContent(int index) {
return content_.get(index);
}
/**
* <code>repeated bytes content = 1;</code>
*/
public Builder setContent(
int index, com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
ensureContentIsMutable();
content_.set(index, value);
onChanged();
return this;
}
/**
* <code>repeated bytes content = 1;</code>
*/
public Builder addContent(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
ensureContentIsMutable();
content_.add(value);
onChanged();
return this;
}
/**
* <code>repeated bytes content = 1;</code>
*/
public Builder addAllContent(
java.lang.Iterable<? extends com.google.protobuf.ByteString> values) {
ensureContentIsMutable();
super.addAll(values, content_);
onChanged();
return this;
}
/**
* <code>repeated bytes content = 1;</code>
*/
public Builder clearContent() {
content_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000001);
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:signalservice.ByteArrayList)
}
static {
defaultInstance = new ByteArrayList(true);
defaultInstance.initFields();
}
// @@protoc_insertion_point(class_scope:signalservice.ByteArrayList)
}
private static com.google.protobuf.Descriptors.Descriptor
internal_static_signalservice_ByteArrayList_descriptor;
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_signalservice_ByteArrayList_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\013Utils.proto\022\rsignalservice\" \n\rByteArra" +
"yList\022\017\n\007content\030\001 \003(\014B*\n\034org.session.li" +
"bsignal.protosB\nUtilProtos"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
public com.google.protobuf.ExtensionRegistry assignDescriptors(
com.google.protobuf.Descriptors.FileDescriptor root) {
descriptor = root;
internal_static_signalservice_ByteArrayList_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_signalservice_ByteArrayList_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_signalservice_ByteArrayList_descriptor,
new java.lang.String[] { "Content", });
return null;
}
};
com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
}, assigner);
}
// @@protoc_insertion_point(outer_class_scope)
}