AAPT2: Share split functionality between link and optimize
Generating splits should be possible to do from the optimize command.
This means that a lot of infrastructure around split APKs can be
shared by both the optimize and link phase.
Bug: 35925830
Change-Id: Ia88b9e4bff300a56353b2f7a4a2547c8eb43a299
Test: manual
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
new file mode 100644
index 0000000..15114e8
--- /dev/null
+++ b/tools/aapt2/io/Util.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io/Util.h"
+
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+namespace aapt {
+namespace io {
+
+bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std::string& out_path,
+ uint32_t compression_flags, IArchiveWriter* writer) {
+ if (context->IsVerbose()) {
+ context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive");
+ }
+
+ if (!writer->WriteFile(out_path, compression_flags, in)) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
+ << " to archive: " << writer->GetError());
+ return false;
+ }
+ return true;
+}
+
+bool CopyFileToArchive(IAaptContext* context, io::IFile* file, const std::string& out_path,
+ uint32_t compression_flags, IArchiveWriter* writer) {
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ if (!data) {
+ context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "failed to open file");
+ return false;
+ }
+ return CopyInputStreamToArchive(context, data.get(), out_path, compression_flags, writer);
+}
+
+bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::MessageLite* proto_msg,
+ const std::string& out_path, uint32_t compression_flags,
+ IArchiveWriter* writer) {
+ if (context->IsVerbose()) {
+ context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive");
+ }
+
+ if (writer->StartEntry(out_path, compression_flags)) {
+ // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->FinishEntry().
+ {
+ // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
+ ::google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+ if (!proto_msg->SerializeToZeroCopyStream(&adaptor)) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
+ << " to archive");
+ return false;
+ }
+ }
+
+ if (writer->FinishEntry()) {
+ return true;
+ }
+ }
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
+ << " to archive: " << writer->GetError());
+ return false;
+}
+
+bool Copy(OutputStream* out, InputStream* in) {
+ const void* in_buffer;
+ size_t in_len;
+ while (in->Next(&in_buffer, &in_len)) {
+ void* out_buffer;
+ size_t out_len;
+ if (!out->Next(&out_buffer, &out_len)) {
+ return !out->HadError();
+ }
+
+ const size_t bytes_to_copy = in_len < out_len ? in_len : out_len;
+ memcpy(out_buffer, in_buffer, bytes_to_copy);
+ out->BackUp(out_len - bytes_to_copy);
+ in->BackUp(in_len - bytes_to_copy);
+ }
+ return !in->HadError();
+}
+
+} // namespace io
+} // namespace aapt