diff options
author | Scott Lobdell <slobdell@google.com> | 2019-01-31 11:53:41 -0800 |
---|---|---|
committer | Scott Lobdell <slobdell@google.com> | 2019-02-01 14:08:42 -0800 |
commit | 88b45c586d461df38b866d529bc98d1dfa3e8838 (patch) | |
tree | ae57a86275dac94c0899015923778f3016c865b2 /startop/view_compiler/dex_layout_compiler.cc | |
parent | 067596650927fa91a97355e84b152b21826f7ae2 (diff) | |
parent | 9b9ca46fc2d3da231bf9ef6ff630105720f94cf2 (diff) |
Merge QP1A.190122.001
Conflicts:
api/system-current.txt
core/java/android/bluetooth/BluetoothAdapter.java
core/jni/android_util_Process.cpp
core/jni/com_android_internal_os_Zygote.cpp
core/res/res/values/config.xml
core/res/res/values/symbols.xml
media/java/android/media/MediaCodecInfo.java
packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
services/core/java/com/android/server/ConnectivityService.java
services/core/java/com/android/server/LocationManagerService.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
services/core/java/com/android/server/location/GnssLocationProvider.java
services/core/java/com/android/server/wm/ActivityStack.java
services/net/java/android/net/ip/IpClient.java
telecomm/java/android/telecom/Connection.java
telephony/java/android/telephony/ims/ImsCallSession.java
telephony/java/android/telephony/ims/ImsCallSessionListener.java
telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
wifi/java/android/net/wifi/WifiConfiguration.java
Change-Id: I367301986f2ae80a528050c3d78776b5a4c6b5ee
Diffstat (limited to 'startop/view_compiler/dex_layout_compiler.cc')
-rw-r--r-- | startop/view_compiler/dex_layout_compiler.cc | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/startop/view_compiler/dex_layout_compiler.cc b/startop/view_compiler/dex_layout_compiler.cc new file mode 100644 index 000000000000..c68793d10399 --- /dev/null +++ b/startop/view_compiler/dex_layout_compiler.cc @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2018 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 "dex_layout_compiler.h" +#include "layout_validation.h" + +#include "android-base/stringprintf.h" + +namespace startop { + +using android::base::StringPrintf; + +void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) { + if (0 == name.compare(u"merge")) { + message_ = "Merge tags are not supported"; + can_compile_ = false; + } + if (0 == name.compare(u"include")) { + message_ = "Include tags are not supported"; + can_compile_ = false; + } + if (0 == name.compare(u"view")) { + message_ = "View tags are not supported"; + can_compile_ = false; + } + if (0 == name.compare(u"fragment")) { + message_ = "Fragment tags are not supported"; + can_compile_ = false; + } +} + +DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method) + : method_{method}, + context_{dex::Value::Parameter(0)}, + resid_{dex::Value::Parameter(1)}, + inflater_{method->MakeRegister()}, + xml_{method->MakeRegister()}, + attrs_{method->MakeRegister()}, + classname_tmp_{method->MakeRegister()}, + xml_next_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser"), "next", + dex::Prototype{dex::TypeDescriptor::Int()})}, + try_create_view_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), "tryCreateView", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"), + dex::TypeDescriptor::FromClassname("android.view.View"), + dex::TypeDescriptor::FromClassname("java.lang.String"), + dex::TypeDescriptor::FromClassname("android.content.Context"), + dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})}, + generate_layout_params_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "generateLayoutParams", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams"), + dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})}, + add_view_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "addView", + dex::Prototype{ + dex::TypeDescriptor::Void(), + dex::TypeDescriptor::FromClassname("android.view.View"), + dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams")})}, + // The register stack starts with one register, which will be null for the root view. + register_stack_{{method->MakeRegister()}} {} + +void DexViewBuilder::Start() { + dex::DexBuilder* const dex = method_->dex_file(); + + // LayoutInflater inflater = LayoutInflater.from(context); + auto layout_inflater_from = dex->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), + "from", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), + dex::TypeDescriptor::FromClassname("android.content.Context")}); + method_->AddInstruction( + dex::Instruction::InvokeStaticObject(layout_inflater_from.id, /*dest=*/inflater_, context_)); + + // Resources res = context.getResources(); + auto context_type = dex::TypeDescriptor::FromClassname("android.content.Context"); + auto resources_type = dex::TypeDescriptor::FromClassname("android.content.res.Resources"); + auto get_resources = + dex->GetOrDeclareMethod(context_type, "getResources", dex::Prototype{resources_type}); + method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_resources.id, xml_, context_)); + + // XmlResourceParser xml = res.getLayout(resid); + auto xml_resource_parser_type = + dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser"); + auto get_layout = + dex->GetOrDeclareMethod(resources_type, + "getLayout", + dex::Prototype{xml_resource_parser_type, dex::TypeDescriptor::Int()}); + method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_layout.id, xml_, xml_, resid_)); + + // AttributeSet attrs = Xml.asAttributeSet(xml); + auto as_attribute_set = dex->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.util.Xml"), + "asAttributeSet", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.util.AttributeSet"), + dex::TypeDescriptor::FromClassname("org.xmlpull.v1.XmlPullParser")}); + method_->AddInstruction(dex::Instruction::InvokeStaticObject(as_attribute_set.id, attrs_, xml_)); + + // xml.next(); // start document + method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_)); +} + +void DexViewBuilder::Finish() {} + +namespace { +std::string ResolveName(const std::string& name) { + if (name == "View") return "android.view.View"; + if (name == "ViewGroup") return "android.view.ViewGroup"; + if (name.find(".") == std::string::npos) { + return StringPrintf("android.widget.%s", name.c_str()); + } + return name; +} +} // namespace + +void DexViewBuilder::StartView(const std::string& name, bool is_viewgroup) { + bool const is_root_view = view_stack_.empty(); + + // xml.next(); // start tag + method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_)); + + dex::Value view = AcquireRegister(); + // try to create the view using the factories + method_->BuildConstString(classname_tmp_, + name); // TODO: the need to fully qualify the classname + if (is_root_view) { + dex::Value null = AcquireRegister(); + method_->BuildConst4(null, 0); + method_->AddInstruction(dex::Instruction::InvokeVirtualObject( + try_create_view_.id, view, inflater_, null, classname_tmp_, context_, attrs_)); + ReleaseRegister(); + } else { + method_->AddInstruction(dex::Instruction::InvokeVirtualObject( + try_create_view_.id, view, inflater_, GetCurrentView(), classname_tmp_, context_, attrs_)); + } + auto label = method_->MakeLabel(); + // branch if not null + method_->AddInstruction( + dex::Instruction::OpWithArgs(dex::Instruction::Op::kBranchNEqz, /*dest=*/{}, view, label)); + + // If null, create the class directly. + method_->BuildNew(view, + dex::TypeDescriptor::FromClassname(ResolveName(name)), + dex::Prototype{dex::TypeDescriptor::Void(), + dex::TypeDescriptor::FromClassname("android.content.Context"), + dex::TypeDescriptor::FromClassname("android.util.AttributeSet")}, + context_, + attrs_); + + method_->AddInstruction( + dex::Instruction::OpWithArgs(dex::Instruction::Op::kBindLabel, /*dest=*/{}, label)); + + if (is_viewgroup) { + // Cast to a ViewGroup so we can add children later. + const ir::Type* view_group_def = method_->dex_file()->GetOrAddType( + dex::TypeDescriptor::FromClassname("android.view.ViewGroup").descriptor()); + method_->AddInstruction(dex::Instruction::Cast(view, dex::Value::Type(view_group_def->orig_index))); + } + + if (!is_root_view) { + // layout_params = parent.generateLayoutParams(attrs); + dex::Value layout_params{AcquireRegister()}; + method_->AddInstruction(dex::Instruction::InvokeVirtualObject( + generate_layout_params_.id, layout_params, GetCurrentView(), attrs_)); + view_stack_.push_back({view, layout_params}); + } else { + view_stack_.push_back({view, {}}); + } +} + +void DexViewBuilder::FinishView() { + if (view_stack_.size() == 1) { + method_->BuildReturn(GetCurrentView(), /*is_object=*/true); + } else { + // parent.add(view, layout_params) + method_->AddInstruction(dex::Instruction::InvokeVirtual( + add_view_.id, /*dest=*/{}, GetParentView(), GetCurrentView(), GetCurrentLayoutParams())); + // xml.next(); // end tag + method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_)); + } + PopViewStack(); +} + +dex::Value DexViewBuilder::AcquireRegister() { + top_register_++; + if (register_stack_.size() == top_register_) { + register_stack_.push_back(method_->MakeRegister()); + } + return register_stack_[top_register_]; +} + +void DexViewBuilder::ReleaseRegister() { top_register_--; } + +dex::Value DexViewBuilder::GetCurrentView() const { return view_stack_.back().view; } +dex::Value DexViewBuilder::GetCurrentLayoutParams() const { + return view_stack_.back().layout_params.value(); +} +dex::Value DexViewBuilder::GetParentView() const { + return view_stack_[view_stack_.size() - 2].view; +} + +void DexViewBuilder::PopViewStack() { + const auto& top = view_stack_.back(); + // release the layout params if we have them + if (top.layout_params.has_value()) { + ReleaseRegister(); + } + // Unconditionally release the view register. + ReleaseRegister(); + view_stack_.pop_back(); +} + +} // namespace startop
\ No newline at end of file |